python基础语法全解(两万字讲解,建议收藏)

文章目录

  • 1.常量和表达式
  • 2.变量与类型
  • 2.1 变量的语法
  • 2.1.1 定义变量
  • 2.1.2 变量命名规则
  • 2.1.3 使用变量
  • 3. 变量的类型
  • 3.1 整型
  • 3.2 浮点型
  • 3.3 字符串
  • 3.4 布尔类型
  • 3.5 为什么需要多种类型
  • 3.6 动态类型
  • 4.注释
  • 4.1 注释语法
  • 4.1.1 注释行
  • 4.1.2 文档字符串
  • 4.1.3 注释的规范
  • 5.输入输出
  • 5.1 通过控制台输出
  • 5.2 通过控制台输入
  • 6.运算符
  • 6.1 算术运算符
  • 6.2 关系运算符
  • 6.3 逻辑运算符
  • 6.4 赋值运算符
  • 7.顺序语句
  • 8.条件语句
  • 8.1 语法格式
  • 9.缩进与代码块
  • 10.空语句 pass
  • 11.循环语句
  • 11.1 while循环
  • 11.2 for循环
  • 11.3 continue与break
  • 12.函数
  • 12.1 语法格式
  • 12.2 函数参数
  • 12.3 函数的返回值
  • 12.4 变量作用域
  • 12.5 函数的执行过程
  • 12.6 链式调用
  • 12.7 嵌套调用
  • 12.8 函数栈帧
  • 12.9 函数递归
  • 12.10 参数默认值
  • 12.11 关键词参数
  • 13.列表与元组
  • 13.1 创建列表
  • 13.2 下标访问
  • 13.3 切片操作
  • 13.4 遍历列表元素
  • 13.5 新增元素
  • 13.6 查找元素
  • 13.7 删除元素
  • 13.8 连接列表
  • 13.9 关于元组
  • 14. 字典
  • 14.1 创建字典
  • 14.2 查找key
  • 14.3 新增修改元素
  • 14.4 删除元素
  • 14.5 遍历字典元素
  • 14.6 取出所有key和value
  • 14.7 合法的key类型
  • 15.文件
  • 15.1 文件是什么
  • 15.2 文件路径
  • 15.3 文件操作
  • 15.3.1 打开文件
  • 15.3.2 关闭文件
  • 15.3.3 写文件
  • 15.3.4 读文件
  • 15.4 关于中文的处理
  • 15.5 使用上下文管理器
  • 1.常量和表达式

    我们可以把Python当成一个计算器,来进行一些算术运算。

    print(1+2+3)
    print(2*9)
    print(9/2)
    
    #打印结果
    #6
    #18
    #4.5
    

    print是python的一个内置函数,功能就是打印到显示器中。

  • 在运算符和数字间,可以没有空格也可以存在空格,为了美观通过会带有一个空格。
  • 值得注意的是,在python中直接/结果是会保留一位整数的,这点和C/C++以及Java是不同的。不过你想要取整的化可以使用2 // 3来执行。

    2.变量与类型

    在C/C++中,当我们要进行计算时,通过需要把一些计算的中间过程保存起来,这个时候需要使用到变量了。

    a = 1
    b = 2
    c = a+b
    print(c)
    #打印结果:3
    

    这里的a,b,c就是变量。
    变量可以视为一块能够容纳数据的空间,这个空间往往对应到内存这样的硬件上。

    2.1 变量的语法

    2.1.1 定义变量

    a = 100
    # a为变量名   = 为赋值运算符    100为变量的赋值
    

    通过定义变量,如果你学过C/C++或者Java你会发现。这里没有确定变量的类型,其实在python中中是不需要确定变量的类型,其类型会根据你的赋值,自动定义。

    2.1.2 变量命名规则

  • 变量名由数字字母下划线构成。
  • 数字不能开头。
  • 变量名不能和关键字重复。
  • 变量名区分大小写。
  • 变量名尽量使用有意义的单词来命名。
  • 当变量名由多个单词组成时,建议使用“驼峰命名法”,比如:totalCount,除了首个单词外,其余单词首字母大写。
  • 2.1.3 使用变量

    读取变量的值

    a = 10
    print(a)
    

    修改变量的值

    a = 10
    a = 20
    print(a)
    

    值得注意的是,因为python当成定义不需要确定类型的缘故,修改变量的值和定义变量的时看起来是没有区别的
    赋值给其他变量

    a = 10
    b = a
    print(a)
    print(b)
    

    3. 变量的类型

    变量里面存储的不仅仅是数字,还可以存储其他种类的数据,我们引入了类型这样的概念。
    上文也说了,python和C/C++/Java是不同的,不需要显式指定,而是在赋值的时候确定的。
    那么如何知道python中的类型呢?
    python提供了type这个内置函数。

    a = 10#整型
    b = 1.1#浮点型
    c = "abc"#字符串
    d = True#布尔类型
    print(type(a))
    print(type(b))
    print(type(c))
    print(type(d))
    """
    打印结果
    <class 'int'>
    <class 'float'>
    <class 'str'>
    <class 'bool'>
    """
    

    3.1 整型

    和C++/java等语言不同,python的int类型变量,表示的数据范围是没有上限的,只要内存足够,理论上是可以无限大的。

    3.2 浮点型

    与C++/java等语言不同,python的小数只有float一种类型,没有double类型,但实际上python中的float就相当于C++/java中的double,表示双精度浮点数。

    3.3 字符串

    在python中使用''或者""都可以表示字符串。
    可以利用内置函数len来测量字符串的长度。

    a = 'abcdef'
    print(len(a))
    # 打印结果: 6
    

    可以使用+来对两个字符串进行连接。

    a = 'hello '
    b = 'yui'
    print(a+b)
    #打印结果:hello yui
    

    注意不要用不同类型的变量进行相加。

    3.4 布尔类型

    True 表示真
    False 表示假
    

    用于逻辑判断。

    3.5 为什么需要多种类型

    1. 类型决定了数据在内存中占据的多大空间。
    2. 类型其实也确立你能对这个变量进行怎么的操作。

    3.6 动态类型

    在python中,一个变量是什么类型,是可以在程序运行过程中改变的,这个特性称为动态类型

    a = 10
    print(type(a))
    a = "hahaha"
    print(type(a))
    '''
    <class 'int'>
    <class 'str'>
    '''
    

    在程序运行过程中a的类型由int变成了str

    C++/java这种语言是不允许这样的操作的,一个变量定义类型后就固定了。这样的特性就被称为静态类型。

    动态类型,尽管会大大节约代码量,但是对于非本代码的创造者来说是会增加阅读难度的。

    4.注释

    在前面的代码中我已经在运用注释了,那么注释是什么呢?
    注释是一种对代码的解释,能够帮助程序员能好的理解代码,同时不会影响程序的运行。

    在初期的代码量极少的情况下,注释的作用可能可有可无,但是一旦开始写一些复杂的程序时,注释的作用就非常的大了,如果某段代码你长时间没有接触后在次接触时,注释会为你节约大量的理解时间,对于他人同样如此。

    4.1 注释语法

    4.1.1 注释行

    使用#开始的行都是注释。

    #注释
    

    4.1.2 文档字符串

    使用三引号引起来的称为文档字符串,也可以将其视为一种注释。

  • 可以包括多行内容。
  • 一般放在文件/函数/类的开始。
  • '''或者"""都可。
  • '''
    文档字符串
    文档字符串
    文档字符串
    '''
    

    4.1.3 注释的规范

    1. 内容准确:注释内容要和代码一致,匹配,并在代码修改时及时更新。
    2. 篇幅合理:注释不应该太精简,同时也不能篇幅太长。

    5.输入输出

    为了和用户进行交互。

  • 用户把信息传递给程序的过程,称为输入。
  • 程序把结果展示给用户的过程,称为输出。
    输入和输出最基本的方法就是控制台,用户提供控制台输入一些字符串,程序在通过控制台打印一些字符串。
  • 5.1 通过控制台输出

    使用内置函数print输出到控制台

    print('hello!!!!!!!!')
    

    输出num = 100

    num = 100
    print(f'num = {num}')
    #打印结果:num = 100
    
  • 使用f表示作为前缀的字符串,称为f-string
  • 里面可以使用{}来内嵌一个其他变量的/表达式。
  • 5.2 通过控制台输入

    python使用input函数来读取用户的输入。

    num = 0
    num = input('请输入一个整数:')
    print(f'你输入的整数是:{num}')
    '''
    请输入一个整数:1000
    你输入的整数是:1000
    '''
    
  • input的参数相当于一个提示信息,可有可无,看需求。
  • input的返回值就是用户输入的内容,是字符串类型
  • a = input('请输入第一个整数:')
    b = input('请输入第二个整数:')
    print(f'a + b = {a+b}')
    '''
    请输入第一个整数:12
    请输入第二个整数:34
    a + b = 1234
    '''
    

    这里的+是字符串拼接。
    为了避免这种情况,我们需要进行类型转化。

    a = int(input('请输入第一个整数:'))
    b = int(input('请输入第二个整数:'))
    print(f'a + b = {a+b}')
    '''
    请输入第一个整数:12
    请输入第二个整数:34
    a + b = 46
    '''
    

    6.运算符

    6.1 算术运算符

    + - * / % ** //这些进行算术运算的运算符都是算术运算符。

  • 整数/整数结果可能是小数,而不会截断。
  • %是求余数的意思。
  • **是求乘方,不光能算整数次方,而可以计算小数次方。
  • //是取整除法,当结果为小数时,会像下取整。
  • 6.2 关系运算符

    < <= > >= == !=这一系列的运算符被称为关系运算符,它们是在比较操作数间的关系。

  • <= 小于等于
  • >=大于等于
  • ==等于
  • !=不等于
    一旦关系表达式符合,那么表达式会返回True,如果不符合,表达式会返回False
  • a = 100
    b = 10
    print(a == b)
    print(a != b)
    print(a > b)
    print(a >= b)
    print(a > b)
    print(a <= b)
    '''
    False
    True
    True
    True
    True
    False
    '''
    

    除此之外,python还可以进行字符串的比较。

    a = 'hello'
    b = 'world'
    print(a == b)
    print(a != b)
    print(a > b)
    print(a >= b)
    print(a > b)
    print(a <= b)
    '''
    False
    True
    False
    False
    False
    True
    '''
    
  • 直接使用 == 或者!= 即可对字符串内容判断相等。
  • 字符串比较大小,规则是字典序。
    对于浮点数来说,不能使用 == 判定相等。
  • print(0.1+0.2 == 0.3)
    # False
    print(0.1+0.2)
    #0.30000000000000004
    

    浮点数在计算机中的表示并不是精确的,在计算过程中,容易出现非常小的误差。
    为此我们只能自己限定一个误差范围来进行比较。

    a = 0.1+0.2
    b = 0.3
    print(-0.000001<(a-b)<0.000001)
    

    6.3 逻辑运算符

    ans or not这一系列的运算符称为逻辑运算符。

  • and 表示 特点:一假则假
  • or 表示 特点:一真则真
  • not 表示 特点:真假转换
  • a = 10
    b = 20
    c = 30
    print(a < b and b < c)
    print(a < b and b > c)
    print(a > b or b > c)
    print(a < b or b > c)
    print(not a < b)
    print(not a > b)
    '''
    True
    False
    False
    True
    False
    True
    '''
    

    在python中a<b and b<c可以写成a<b<c这个设定和大部分编程语言都不一样。
    关于短路问题

  • 对于and,如果左侧表达式为False,整体一定为False,右侧表达式不再执行。
  • 对于or,如果左侧表达式为True,整体一定为True,右侧表达式不再执行。
  • 6.4 赋值运算符

    对于=的使用
    =是表达赋值的意思,要和==区分
    链式赋值

    a = b = c = 100
    

    多元赋值

    a,b = 10,100
    

    利用多元赋值实现两个变量的交换。

    # 常规写法
    a = 10
    b = 20
    tmp = 10
    a = b
    b = tmp
    
    #多元赋值
    a = 10
    b = 20
    a,b = b,a
    

    复合赋值运算符
    python还有一些复合赋值运算符,比如:+= -= *= /= %=

    # a += 1 等同于 a = a+1
    a = 10
    a = a + 1
    print(a)
    
    a = 10
    a += 1
    print(a)
    #11
    #11
    

    注意:python中不支持++ --这种自增/自减运算符。

    7.顺序语句

    默认情况下,python的代码都是按照从上到下的顺序依次执行的。

    print('hello ')
    print('world')
    

    结果一定是hello world。写代码是一件有条理的事情,只有安排好任务的顺序,计算机才可以准确的执行任务。

    8.条件语句

    条件语句能够表达,如果…那么的意思。这构成了计算机中的逻辑判断。
    条件语句也可以叫做分支/选择语句,因为它真的将程序的执行分成了多条路。
    ![[Pasted image 20240629135602.png]]
    在生活中经常有人说如果怎么这么样,就会怎么这么样。这就是一个选择语句,如果满足这个条件就会进入相应的事件。就像galgame当中选择合适的选项就可以进入相应人物的故事线,将其攻略。这就是选择!

    8.1 语法格式

    if语句

    if expression:
    	do_something1
    	do_something2
    next_something
    

    只有当expression为True时才会执行do_something1 do_something2和next_something。
    否则只会执行next_something。

    if else

    if expression:
    	do_something1
    else:
    	do_something2
    

    当expression为True时,执行do_something1
    否则执行do_something2

    if elif else

    if expression1:
    	do_something1
    elif expression2:
    	do_something2
    else:
    	do_something3
    

    如果expression1为True,执行do_something1。
    如果expression1为False,且expression2为True,执行do_something2。
    如果expression1为Flase,且expression3为False,执行do_something3。

    注意:如果你已经学过其他的编程语言,可能会觉得python和大多数的语言不太一样。

  • if后面的条件表达式,没有(),使用:作为结尾。
  • if/else 条件满足时执行的语句块,使用缩进。不再使用{}
  • 对于多条件分支,不是写作else if,而是写作elif。
  • #学习python的态度
    choice = input("输入 1 表达好好学习python,输入 2 表达躺平摆烂\n")
    if choice == '1':
    	print('成为python领域高手')
    elif choice == '2':
    	print('成为躺平领域高手')
    else :
    	print('输入错误')
    

    9.缩进与代码块

    代码块指的是一组放在一起执行的代码。
    子啊python使用缩进来表示代码块,不同级别的缩进,程序的执行效果是不同的。
    写一个多层的if语句嵌套来感受一下。

    if a == 1:
    	if b == 2:
    		if c == 3:
    			if d == 4:
    				if e == 5:
    					print('haha')
    				print('d == 4')
    			print('c == 3')
    

    大家觉得怎么样呢?至此江湖上便流传了写python需要自备游标卡尺的传说。

    一些小练习

    1. 输入一个整数,判断是否是奇数。
    2. 输入一个整数判断是正数还是负数。
    3. 判断年份是否是闰年。
    #1
    num = int(input('输入一个整数:'))
    if num%2 == 0:
    	print('num是偶数')
    else:
    	print('num是奇数')
    
    #2
    num = int(input('输入一个整数:'))
    if num>0:
    	print('num是正数')
    elif num<0:
    	print('num是负数')
    else:
    	print('num是0')
    
    #3
    year = int(input('请输入一个公元年份:'))
    if (year%4 == 0 and year%100 != 0) or year%400 == 0:
    	print('year是闰年')
    else:
    	print('year是平')
    

    10.空语句 pass

    a = int(input('输入一个整数:'))
    if a == 1:
    	print('hello')
    
    #等价于
    a = int(input('输入一个整数:'))
    if a != 1:
    	pass
    else:
    	print('hello')
    

    pass就是一个空语句,就相等于C语言里的;

    11.循环语句

    有些操作需要反复执行的,这种就需要使用到循环语句。

    11.1 while循环

    语法格式:

    while expression:
    	do_something#循环体
    
  • expression为True,执行do_something。
  • expression为False,结束循环。
  • #打印1~10的整数
    num = 1
    while num<=10:
    	print(num)
    	num+=1
    #计算1+2+3+...+100
    num = 1
    sum_ = 0
    while num<=100:
    	sum_+=num
    	num+=1
    print(sum_)
    #奇数10的阶乘
    num = 1
    sou = 1
    while num<=10:
    	sou*=num
    	num+=1
    print(sou)
    

    11.2 for循环

    基本语法

    for 循环变量 in 可迭代对象:
    	循环体
    

    注意:

  • python里的for循环是没有初始化语句、循环条件判断语句,循环变量更新语句的。
  • 所谓的可迭代对象,指的是内部包含多个元素,能一个一个的把啊取出来的特殊变量。
    还是直接看代码,更容易理解。
  • #打印1~10
    for i in range(1,11):
    	print(i)
    
    #打印1~10间的偶数
    for i in range(2,11,2):
    	print(i)
    #打印10~1
    for i in range(10,0,-1):
    	print(i)
    #计算1+2+3+...+100
    sum_ = 0
    for i in range(1,101,1):
    	sum_+=1
    print(sum_)
    

    使用range函数,能生成一个可迭代对象,生成范围为,[)是一个左闭右开的范围,同时range还右第3个参数,可以指定步长,不写的化默认是1。

    11.3 continue与break

    continue表示结束本次循环,进入下一次的循环。

    for i in range(1,10):
    	if i == 5:
    		continue
    	print(i)
    '''
    1
    2
    3
    4
    6
    7
    8
    9
    '''
    
    

    可以发现没有5,5被跳过去了。这就是continue的功能。

    break表示结束整个循环。

    for i in range(1,10):
    	if i == 5:
    		break
    	print(i)
    '''
    1
    2
    3
    4
    '''
    

    可以发现4后面就没有结果了,那是因为循环在5时就已经退出了。

    12.函数

    无论是编程中的函数还是数学中的函数,本质都是差不多的,丢给函数一些值,函数在经过一系列的处理返回一个值。不过编程上函数也可以不返回值就是了。
    可以把编程上的函数理解为一段可以重复使用的代码片段.

    求一段区间的和。

    #求1~100的和
    sum = 0
    for i in range(1,101):
    	sum+=1
    print(sum)
    
    #求1~1000的和
    sum = 0
    for i in range(1,1001):
    	sum+=i
    print(sum)
    
    #求20~40的和
    sum = 0
    for i in range(20,41):
    	sum+=i
    print(sum)
    

    这3段代码都同质化严重,就只有for循环之中的范围变了,那么我们就可以把其写为一个函数来多次调用。

    #定义函数
    def calcSum(left,right):
    	sum = 0
    	for i in range(left,right):
    		sum+=i
    	print(sum)
    #调用函数
    calcSum(1,101)
    calcSum(1,1001)
    calcSum(20,41)
    '''
    5050
    500500
    630
    '''
    

    是不是很简洁,这就是函数的运用,把重复的代码给消除了。

    12.1 语法格式

    创建函数/定义函数

    def 函数名(形参列表):
    	函数体
    	return 返回值
    

    调用函数/使用函数

    函数名(实参列表)#不考虑返回值
    返回值 = 函数名(实参列表)#考虑返回值
    

    函数只有在被调用时才会执行。

    函数必须先定义再使用

    test()
    
    def test():
    	print('hahaha')
    

    此时会报错,因为还没有定义就执行了。

    12.2 函数参数

    在函数定义的时候,可以在()中指定形式参数简称形参,然后在调用时,由调用者把实际参数简称实参,传递过去。
    这样就可以做到一份函数,针对不同的数据进行计算处理。

    #定义函数
    def calcSum(left,right):
    	sum = 0
    	for i in range(left,right):
    		sum+=i
    	print(sum)
    #调用函数
    calcSum(1,101)
    calcSum(1,1001)
    calcSum(20,41)
    

    在这个代码中,left right就是函数的形参,1,100...就是函数的实参。
    注意:

  • 一个函数可以由一个形参,也可以有多个形参,也可以没有形参。
  • 一个函数的形参有几个,那么传递实参的时候也要传相应的个数,保证个数匹配。
  • 和C++/java不同,python是动态类型的编程语言,函数的形参不必指定参数类=类型,也就是说一个函数可以支持多种不同类型的参数,类似于函数重载。
  • def test(tmp):
    	print(tmp)
    test(10)
    test('hahaha')
    test(False)
    '''
    10
    hahaha
    False
    '''
    

    12.3 函数的返回值

    函数的参数可以视为函数的输入,那么函数的返回值就可以视为函数的输出

    为了方便理解,我们可以把函数想象成一个工厂,所谓的函数输入就是提供给工厂的原材料,函数输出就工厂提供的产品。

    还是上面的求和函数

    ##无返回值
    #定义函数
    def calcSum(left,right):
    	sum = 0
    	for i in range(left,right):
    		sum+=i
    	print(sum)
    #调用函数
    calcSum(1,101)
    
    ##有返回值
    def calcSum(left,right):
    	sum = 0
    	for i in range(left,right):
    		sum+=i
    	return sum
    #调用函数
    print(calcSum(1,101))
    

    这两种代码的区别就在于,前者直接子啊函数的内部就打印了,后者使用了return语句把结果返回給函数的调用者,再有调用者负责打印。

    为了满足逻辑和用户交互分离的编程原则,第二种写法更好。在第一种写法中,然后后续我们需要保存结果到文件中,或者通过网络发送,第一种写法就难以胜任了。而第二种写法只负责计算逻辑不负责和用户交互,那么就会有更多的搭配可以实现。

    一个函数可以有多个return语句。

    #判断一个整数是否为奇数
    def isOdd(num):
    	if num%2 == 0:
    		return False
    	else:
    		return True
    x = int(input("输入一个整数:"))
    ret = isOdd(x)
    print(ret)
    

    执行到return语句函数便会退出,回到开始调用的位置。
    验证:

    #判断一个整数是否为奇数
    def isOdd(num):
    	if num%2 == 0:
    		return False
    	return True
    ret = isOdd(10)
    print(ret)
    

    num是偶数,返回Flase后不会再返回True了。

    python可以同时返回多个值,使用,来分割多个返回值。

    def test():
    	a = 100
    	b = 200
    	return a,b
    x,y = test()
    print(x)
    print(y)
    '''
    100
    200
    '''
    

    如果需要关注其中的部分返回值,可以使用_来忽略不需要的返回值。

    def test():
    	a = 100
    	b = 200
    	return a,b
    _,y = test()
    print(y)
    # 200
    

    12.4 变量作用域

    def test():
    	a = 100
    	b = 200
    	return a,b
    a,b = test()
    

    观察代码,函数内外部存在相同命名的变量。但其实这两组变量是不同的变量,只是名字相同,它们的地址是不会相同的。
    每个变量都有它们的作用域,变量只能在自己的作用域中生效。

    def test():
    	a = 100
    	b = 200
    	return a
    print(a)
    # error name 'a' is not defined
    

    在不同的作用域中,允许存在不同同名的变量。

    x = 10
    def test():
    	x = 100
    	print(f'函数内部x = {x}')
    test()
    print(f'函数外部x = {x}')
    '''
    函数内部x = 100
    函数外部x = 10
    '''
    
  • 在函数内部的变量,称为局部变量。
  • 不在任何函数内部的变量,也称为全变量。
    如果函数内部尝试访问的变量在局部不存在就会尝试去全局去寻找。
  • x = 100
    def test():
    	print(f'x = {x}')
    test()
    # 100
    

    如果想要在函数内部修改全局变量的值,需要使用global关键字声明。

    x = 100
    def test():
    	global x
    	x = 10
    	print(f'函数内部x = {x}')
    test()
    print(f'函数外部x = {x}')
    '''
    函数内部x = 10
    函数外部x = 10
    '''
    

    如果没有global的声明的话,系统会认为x = 10是一个新创建的局部变量。

    if/while/for等语句不会影响到变量作用域,也就是说,在if/while/for中定义的变量,在语句外也可以正常使用。

    for i in range(1,10):
    	print(f'函数内部 i = {i}')
    print(f'函数外部 i = {i}')
    

    12.5 函数的执行过程

  • 调用函数才会执行函数体代码,不调用就不会执行。
  • 函数体执行结束(或者遇到return语句)则会回到函数调用位置,继续往下执行。
  • def test():
    	print('hahaha')
    	print('hahaha')
    print('xixixi')
    test()
    print('xixixi')
    

    12.6 链式调用

    其实前面我们已经用过链式调用了

    ##有返回值
    def calcSum(left,right):
    	sum = 0
    	for i in range(left,right):
    		sum+=i
    	return sum
    #调用函数
    print(calcSum(1,101))#链式调用
    

    把一个函数的返回值,作为另一个函数的参数就是链式调用

    12.7 嵌套调用

    函数内部还可以调用其他的函数,这叫做嵌套调用。

    def testPrint():
    	print('嵌套调用')
    	print('嵌套调用')
    	print('嵌套调用')
    

    test函数内调用了print函数
    一个函数里面可以嵌套调用任意多个函数。
    函数嵌套的过程是非常灵活的。

    def a():
    	print('a')
    def b():
    	a()
    	print('b')
    def c():
    	b()
    	print('c')
    c()
    '''
    a
    b
    c
    '''
    

    12.8 函数栈帧

    函数之间的调用关系,在python中会使用一个特定的数据结构来表示,称为函数调用栈。每次的函数调用,都会在调用栈里新增一个元素,称为栈帧
    每个函数的局部变量都包含在自己的栈帧中

    12.9 函数递归

    递归是嵌套调用中的一种特殊情况,就是自己调用自己。

    程序调用自身的编程技巧称为递归(recursion)
    递归作为一种算法在程序设计语言中广泛应用.一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型问题层层转化为一个于原问题相似的规模较小的问题来求解.
    递归策略
    只需要少量的代码就可以描述出解题所需要的多重计算,大大的减少程序的代码量.
    递归的主要思想在于:把大事化小

    #计算10的阶乘
    def factor(n):
    	if n == 1:
    		return 1
    	return n*factor(n-1)
    print(factor(10))
    ## 3628800
    

    注意:递归代码要保证

  • 存在限制条件,当满足这个限制条件的时候,递归便不在继续。
  • 每次递归调用之后越来越接近这个限制条件。
    递归的优点
  • 递归类似于数学归纳法明确初始条件,盒递推公式,就可以解决一系列的问题。
  • 递归的代码量往往很少。
    递归的缺点
  • 递归代码往往难以理解,很容易超出操控范围。
  • 递归代码容易出现栈溢出的问题。
  • 递归代码往往可以转换成等价的循环代码,并且通常来说,循环版本的代码效率更高。
  • 12.10 参数默认值

    Python中的函数,可以给形参指定默认值。
    带有默认值的参数,可以子啊调用的时候不传参。即缺省参数

    def add(x,y,debug = False):
    	if debug:
    		print("haha")
    	return x+y
    print(add(1,2))
    print(add(10,20,True))
    
    '''
    3
    haha
    30
    '''
    

    注意:带有默认值的参数需要放到没有默认值得参数后面

    12.11 关键词参数

    在调用函数得时候,需要给函数指定实参,一般默认情况下是按照形参得顺序,来传递实参的。但是我们也可以通过关键字参数,来调整这里的传参顺序,显式指定当前实参传递给哪个形参。

    def test(x,y):
    	print(f'x = {x}')
    	print(f'y = {y}')
    test(x = 10,y = 20)
    test(y = 111,x = 222)
    
    '''
    x = 10
    y = 20
    x = 222
    y = 111
    '''
    

    13.列表与元组

    在编程中,经常需要使用变量来保存数据,如果数据比较少,我们创建几个变量也就算了,那如果数据很多呢。

    a = 1
    b = 2
    c = 3
    ...
    

    甚至有些时候数据多到你都不清楚到底有多少,那么就需要使用到列表了。
    列表是一种让程序员再代码中批量表示/保存数据的方式

    那什么是元组呢?
    元组和列表相比,非常类似。区别再于列表中放哪些元素可以修改调整,元组中放的元素是创建元组时就设定好的,不能修改调整。

    这点也就说明列表是动态的而元组是静态的。其实也就相当于C语言的数组,一个是动态数组,一个是动态数组。

    13.1 创建列表

  • 创建列表主要有两种方式[]表示一个空列表。
  • alist = [] #1
    alist = list()#2
    print(type(alist))
    
    #<class 'list'>
    
  • 如果需要初始化,直接把你想要初始化的值放到[]中就可以了。
    可以直接使用print来打印list中的元素。
  • alist = [1,2,3,4,5]
    print(alist)
    # [1, 2, 3, 4, 5]
    
  • 要注意的是,列表是允许存放不同类型的数据的。这点和C++/java就很不同。
  • alist = [1,'hahhaaa',1.0]
    print(alist)
    #[1, 'hahhaaa', 1.0]
    

    13.2 下标访问

  • 可以通过下标访问操作符[]来获取列表中的任意元素。
    这点就和C语言类似了,通过在[]填写下标索引来访问元素。
  • alist = [1,2,3,4,5]
    print(alist[0])
    # 1
    

    注意:下标是从0开始的,后续依次递增。
    同样我们不仅可以通过下标访问列表元素,还可以通过下标来修改元素。

    alist = [1,2,3,4,5]
    alist[0] = 100
    print(alist[0])
    
    # 100
    

    注意:下标访问时,一定不要超出列表的有效范围,否则会抛出异常,报错的。

    alist = [1,2,3,4,5]
    print(alist[10])
    
    # IndexError: list index out of range
    

    因为下标是从0开始的,因此下标的有效范围[0,列表长度-1],可以使用len函数来获取列表的长度。

    alist = [1,2,3,4]
    print(len(alist))
    
    # 4
    

    特别的是在python中,下标是可以取负值的,表示倒数第几个元素

    alist[-1] = alist[len(alist)-1]
    

    13.3 切片操作

    如果说通过下标操作是一次获取一个数,那么切片操作就是一次获取一个子列表。
    语法:

    使用[:]来进行切片
    
    alist = [1,2,3,4,5]
    print(alist[1:3])
    
    #[2, 3]
    
    alist[1:3]中的1:3使用的是左闭右开的区间,也就是[1,3)
    

    关于切片的特殊操作

    1. 省略边界
    alist = [1,2,3,4,5]
    print(alist[1:]) #省略后边界,表示获取到列表的末尾
    print(alist[:-1]) #省略前边界,表示从列表开头开始获取
    print(alist[:]) #省略两个边界,表示获取整个列表
    '''
    [2, 3, 4, 5]
    [1, 2, 3, 4]
    [1, 2, 3, 4, 5]
    '''
    
    1. 指定步长
    alist = [1,2,3,4,5,6,7,8,9,0]
    print(alist[::1])
    print(alist[::2])
    print(alist[::3])
    print(alist[::4])
    '''
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
    [1, 3, 5, 7, 9]
    [1, 4, 7, 0]
    [1, 5, 9]
    '''
    

    如果指定的步长为负值,则会从后往前遍历。

    alist = [1,2,3,4,5,6,7,8,9,0]
    print(alist[::-1])
    print(alist[::-2])
    print(alist[::-3])
    print(alist[::-4])
    '''
    [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    [0, 8, 6, 4, 2]
    [0, 7, 4, 1]
    [0, 6, 2]
    '''
    

    注意:在切片中填写的数字越界了,不会有负面效果,编译器只会尽可能地把满足条件地元素显示。

    13.4 遍历列表元素

    ‘遍历’指的是把元素一个一个的取出来,再分别进行处理。

  • 最简单就是for循环咯。
  • alist = [1,2,3,4,5]
    for elem in alist:
    	print(elem)
    
    
  • 生成下标访问。
  • alist = [1,2,3,4,5]
    for i in range(0,len(alist)):
    	print(alist[i])
    

    如果是while循环的话。

    alist = [1,2,3,4,5]
    while i < len(alist):
    	print(alist[i])
    	i+=1
    
    

    13.5 新增元素

    使用append方法/函数,向列表末尾插入一个元素。

    alist = [1,2,3,4,5]
    alist.append('elem')
    print(alist)
    
    # [1, 2, 3, 4, 5, 'elem']
    

    使用insert方法/函数,向任意位置插入一个元素。

    alist = [1,2,3,4,5]
    alist.insert(1,'elem') #第一次参数就是要插入的下标位置。
    print(alist)
    
    # [1, 'elem', 2, 3, 4, 5]
    

    13.6 查找元素

  • 使用in操作符,判断元素是否在列表中存在,返回值是布尔类型。
  • alist = [1,2,3,4]
    print(2 in alist)
    print(100 in alist)
    '''
    True
    False
    '''
    
  • 使用index方法,查找元素再列表中的下标,返回值是一个整数,如果元素不存在会报错。
  • alist = [1,2,3,4,5]
    print(alist.index(2))
    print(alist.index(10))
    
    '''
    1
    ValueError: 10 is not in list
    '''
    

    13.7 删除元素

    使用pop方法删除末尾元素,即尾删。

    alist = [1,2,3,4,5]
    alist.pop()
    print(alist)
    '''
    [1, 2, 3, 4]
    '''
    

    同时pop也能根据所提供的下标进行定点删除。

    alist = [1,2,3,4,5]
    alist.pop(2)
    print(alist)
    
    # [1, 2, 4, 5]
    

    如果不知道下标,列表还提供了remove方法,进行删除对应元素的操作

    alist = [1,2,3,4,5,5,5]
    alist.remove(5)
    print(alist)
    
    #[1, 2, 3, 4, 5, 5]
    

    不过只会删除一个元素。

    13.8 连接列表

    使用+可以使连个列表连接起来

    alist = [1,2,3]
    blist = [4,5,6,7]
    print(alist+blist)
    
    # [1, 2, 3, 4, 5, 6, 7]
    

    此处的+是会生成一个新的列表来存储,不会影响到就列表。

    使用extend方法,相当于把一个列表拼接到另一个列表的后面。

  • a.extend(b)是吧b的内容拼接到a的末尾,会改变a,但不会改变b。
  • alist = [1,2,3]
    blist = [4,5,6,7]
    alist.extend(blist)
    print(alist)
    print(blist)
    
    '''
    [1, 2, 3, 4, 5, 6, 7]
    [4, 5, 6, 7]
    '''
    

    13.9 关于元组

    元组的功能和列表相比,基本一致的。
    元组使用()来表示

    atuple = ()
    atuple = tuple()
    

    元组不能修改里面的元素,列表则可以修改里面的元素。
    因此像一些读操作,比如访问下标,切片,遍历,in,index +元组一样支持的。
    但是像写操作 修改元素 新增元素 删除元素 extend元组都是不支持的。
    另外再python中很多时候默认的集合类型就是元组。

    def test():
    	return 1,2
    print(type(test()))
    
    #<class 'tuple'>
    

    为什么python即有列表又有元组呢?
    元组的优势:

  • 你有一个列表, 现在需要调用一个函数进行一些处理. 但是你有不是特别确认这个函数是否会
    把你的列表数据弄乱. 那么这时候传一个元组就安全很多.
  • 下次要讲的字典, 是一个键值对结构. 要求字典的键必须是 “可hash对象” (字典本质上也
    是一个hash表). 而一个可hash对象的前提就是不可变. 因此元组可以作为字典的键, 但是列表
    不行
  • 14. 字典

    字典是一种存储键值对的结构。
    和生活中的字典一样,当你查一个英语的意思时:apple就对应着苹果。它们就是一个键值对,其中apple就是key,而苹果就是value。
    这些键(key)和值(value)是一一对应的,我们可以根据键,快速找到值。

    14.1 创建字典

    创建一个空的字典,使用{}来表示字典。

    a = {}
    b = dict()
    print(type(a))
    print(type(b))
    
    '''
    <class 'dict'>
    <class 'dict'>
    '''
    
  • 可以在创建时同时指定初始值。
  • 键值对之间使用分割,键和值键使用:来分割。
  • 可以使用print来打印字典内容。
  • adict = {'apple': '苹果','world': '世界'}
    print(adict)
    
    # {'apple': '苹果', 'world': '世界'}
    

    如果你想要代码更加的美观,好看,可以这样写:

    adict = {
    	 'apple': '苹果',
    	 'world': '世界'
    }
    
    

    最后一个键值对,后面可写,也可不写。

    14.2 查找key

  • 使用in可以判断key是否在字典中存在,返回布尔值。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界'
    }
    print('apple' in adict)
    print('hello' in adict)
    '''
    True
    False
    '''
    
  • 使用[]通过类似下标访问的方式来获取元素的值,只不过这里的下标是key。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界'
    }
    print(adict['apple'])
    print(adict['world'])
    '''
    苹果
    世界
    '''
    

    如果key值不存在,会抛出异常。
    KeyError: 'xxxxx'

    14.3 新增修改元素

    使用[]可以根据key来新增/修改value。

  • 如果key不存在,对取下标操作赋值,即为新增键值对。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界'
    }
    adict['hello'] = '你好'
    print(adict)
    #{'apple': '苹果', 'world': '世界', 'hello': '你好'}
    
  • 如果key存在,则会修改键值对的值。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界'
    }
    adict['apple'] = '苹果苹果'
    print(adict)
    #{'apple': '苹果苹果', 'world': '世界'}
    

    14.4 删除元素

  • 使用pop方法根据key删除对应的键值对。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界'
    }
    adict.pop('apple')
    print(adict)
    
    # {'world': '世界'}
    

    14.5 遍历字典元素

  • 直接使用for循环能够获取到字典中的所有key,进一步就可以取出每一个值了。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界',
    	 'hello': '你好'
    }
    for key in adict:
    	print(key,adict[key])
    '''
    apple 苹果
    world 世界
    hello 你好
    '''
    

    14.6 取出所有key和value

  • 使用’keys’方法可以获取字典中的所有的key
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界',
    	 'hello': '你好'
    }
    print(adict.keys())
    # dict_keys(['apple', 'world', 'hello'])
    
  • 使用values方法可以获取到字典的所有value
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界',
    	 'hello': '你好'
    }
    print(adict.values())
    
    #dict_values(['苹果', '世界', '你好'])
    
  • 使用items方法可以获取字典中的所有键值对。
  • adict = {
    	 'apple': '苹果',
    	 'world': '世界',
    	 'hello': '你好'
    }
    print(adict.items())
    
    # dict_items([('apple', '苹果'), ('world', '世界'), ('hello', '你好')])
    

    14.7 合法的key类型

    不是所有的类型都可以作为字典的key的,字典的本质其实是哈希表,哈希表的key要求是可哈希的,也就是可以计算出一个哈希值。

  • 可以使用hash函数计算某个对象的哈希值。
  • 但凡能够计算出哈希值的类型,都可以作为字典的key。
  • print(hash(0))  
    print(hash(3.14))  
    print(hash('hello'))  
    print(hash(True))  
    print(hash(()))
    '''
    0
    322818021289917443
    7740487628353429172
    1
    5740354900026072187
    '''
    

    注意:

  • 列表无法计算哈希值。
  • print(hash([1,2,3,4]))
    #TypeError: unhashable type: 'list'
    
  • 字典无法计算哈希值。
  • print(hash({'a': '0'}))
    #TypeError: unhashable type: 'dict'
    

    15.文件

    15.1 文件是什么

    变量是把数据保存到内存中,如果程序重启/断电,内存中的数据就会丢失。
    要想实现数据的持久化存储,就需要把数据存储,就可以把数据存储到硬盘中,也就是在文件中存储。
    一些常见的文件类型:

    文本文件 txt
    可执行文件 exe class 
    图片文件 jpg png
    视频文件 mp4 mov
    office文件 ppt docx
    

    本文主要聚焦于文本文件。

    15.2 文件路径

    在系统中会存在特别多的文件,为了人让这些文件更加全面的被组织,往往会使用很多的文件夹,在Linux也叫目录。
    实际上一个文件往往会进行许多的目录嵌套。为了方便确定一个文件的位置,使用文件路径来描述就很方便了。
    以我存储python代码的路径为例D:\code\python

  • D:表示盘符,不区分大小写。
  • 每个\表示一级目录,当前的python就是放在D盘下的code目录下的。
  • 目录之间的分隔符,可以使用\也可以使用/一般在编写代码时使用/更方便。
    绝对路径于相对路径:
  • 以盘符开头的路径,我们称为绝对路径。
  • 相对路径需要先指定一个基准目录,然后以基准目录位参照点,间接的找到目标文件。
    在描述一个文件路径时,使用绝对路径还是相对路径都是可以的。
  • 15.3 文件操作

    要使用文件,主要通过文件来保存数据,并且在后续把保存数据调出来。为了读写文件,首先当然需要打开文件,在完成操作后在关闭文件。

    15.3.1 打开文件

    使用内建函数open打开文件。

    f = open('d:/test.txt','r')
    
  • 第一个参数是一个字符串,表示要打开的路径。
  • 第二个参数是一个字符串,表示打开方法,其中r表示按读方式打开,w表示按照写方式打开,’a‘表示追加方式打开。
  • 如果文件打开成功,返回一个文件对象,后续的读写文件操作都是围绕这个文件对象展开的。
  • 如果打开文件失败,如指定路径不存在,就会抛出异常。
  • 15.3.2 关闭文件

    使用close方法关闭已打开的的文件。

    f.close()
    

    使用完毕的文件一定要记得关闭。
    一个程序能同时打开的文件数是有限制的

    flist = []
    count = 0
    while True:
    	f = open('d:/tmp/test.txt','r')
    	flist.append(f)
    	count+=1
    	print(f'count = {count}')
    '''
    ...
    count = 8187
    count = 8188
    count = 8189
    Traceback (most recent call last):
      File "d:\code\python\python_test1\test.py", line 158, in <module>
    OSError: [Errno 24] Too many open files: 'd:/tmp/test.txt'
    '''
    

    从代码上来看,大概一个程序是可以打开8000个文件。如果一种循环的打开文件,而不去关闭,就会出现上述问题。当一个程序打开的文件超过上限,就会抛出异常。

    上述代码中,使用一个列表来保存所有文件对象,如果不进行保存,那么python内置的垃圾回收机制就会在文件销毁的时候自动关闭文件。
    但是由于垃圾回收机制不一定及时,所以我们写代码时仍然需要手动回收,避免依赖于自动回收。

    15.3.3 写文件

    文件打开后,就可以写文件了。

  • 写文件,要使用学方法打开,open第二个参数为w
  • 使用write方法写入文件。
  • f = open('d:/tmp/test.txt','w')
    f.write('i am yui')
    f.close()
    

    打开test.txt发现已经写入。
    如果在r方式下写入的话,程序会抛出异常。

    使用w打开文件成功后,原有文件中的数据会清零。
    使用a实现追加写,此时原有内容不变,写入的内容会存在于之前文件内容的末尾。

    f = open('d:/tmp/test.txt','w')
    f.write('i am yui')
    f.close()
    
    f = open('d:/tmp/test.txt','a')
    f.write(',hello')
    f.close()
    
  • 针对已经关闭的文件对象进行写入,程序会抛出异常。
  • 15.3.4 读文件

  • 读文件内容需要使用r方式打开文件。
  • 使用read方法完成读操作,参数表示读取几个字符
  • f = open('d:/tmp/test.txt','r')
    result = f.read(10)
    print(result)
    f.close()
    '''
    i am yui,h
    '''
    
  • 如果文件是多行文本,可以使用for循环一次读取一行。
    我们先构造一个多行的文本文件。
  • 111111
    222222
    333333
    444444
    

    下面来打印这文件的内容。

    f = open('d:/tmp/test.txt','r')
    for line in f:
    	print(f'line = {line}')
    f.close()
    '''
    line = 111111
    
    line = 222222
    
    line = 333333
    
    line = 444444
    
    '''
    

    由于文件里每行的末尾都自带一个换行符,print打印的时候又会默认加上一个换行符,因此打印结果看起来之间存在空格。
    使用

    print(f'line = {line}',end='')
    

    可以取代print自带的换行符。

  • 使用readline直接把文件整个内容读取出来,返回一个列表,每个元素即为一行。
  • f = open('d:/tmp/test.txt','r')
    lines = f.readlines()
    print(lines)
    f.close()
    '''
    ['111111\n', '222222\n', '333333\n', '444444\n']
    '''
    

    15.4 关于中文的处理

    当文件内容出现中文时,读取文件内容可能会出现错误。即出现乱码。
    为什么会出现这种情况呢?
    计算机表示中文的时候,会采取一定的编码方式,被称为字符集

    所谓的“编码方式”,本质就是使用数字表示汉字。
    众所周知,计算机只能表示二进制数据,要想表示英文字母或者汉字或者其他的文字字符,就就要通过编码。
    最简单的字符编码ASCII,使用一个简单的整数就可以表示英文字母和数字,但是如果要表示汉字就需要更大的码表了。
    目前常用的汉字编码方式主要是:GBK和UTF-8.

    为此必须保证文件本身的编码方式,和python代码中读取文件使用的编码方式相一致,才能够避免出错。

    python3默认打开文件的字符集跟随系统,而Windows简体中文版的字符集采用GBK,所以如果文件本身是GBK的编码,直接就能正确处理。如果不是的就会出错。

    15.5 使用上下文管理器

    打开文件后,最容易忘记的就是关闭。python提供了上下文管理器,来帮助我们自动关闭文件。

  • 使用with语句打开文件。
  • 当with内部的代码执行完毕后,就会自动调用关闭方法。
  • with open('d:/tmp/test.txt','r') as f:
    	lines = f.readlines()
    	print(lines)
    '''
    ['111111\n', '222222\n', '333333\n', '444444\n']
    '''
    

    作者:Yui_

    物联沃分享整理
    物联沃-IOTWORD物联网 » python基础语法全解(两万字讲解,建议收藏)

    发表回复