1. 基础

1.1 编码 / 标识符 / 保留字

  1. 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串;
  2. 标识符
    • 第一个字符必须是字母表中字母或下划线_
    • 标识符的其他的部分由字母、数字和下划线组成
    • 标识符对大小写敏感
  3. 保留字即关键字,不能把它们用作任何标识符名称。
    1
    2
    import keyword
    print(keyword.kwlist)

1.2 注释

  1. 单行注释以 # 开头
  2. 多行注释可以用多个#号,或者三个单 / 双引号 ‘’’ 和 “”"
  3. 多行注释中不能再嵌套多行注释,但可以使用单行注释 #
  4. 输出函数的注释
    1
    2
    3
    4
    5
    def a():
    '''函数注释'''
    pass

    print(a.__doc__)

1.3 多行语句

  1. Python 通常是一行写完一条语句,但如果语句很长,可以使用反斜杠来实现多行语句
    1
    2
    3
    total = item_one + \
    item_two + \
    item_three
  2. 在 [], {}, 或 () 中的多行语句,不需要使用反斜杠 \
    1
    2
    total = ['item_one', 'item_two', 'item_three',
    'item_four', 'item_five']

1.4 输出

1.4.1 基本输出

  1. Python 使用 print 输出内容,默认输出是换行的;
  2. 要实现不换行,则需要在变量末尾加上 end=""
    1
    2
    3
    4
    # 换行输出 
    print( x )
    # 不换行输出
    print( x, end="" )

1.4.2 输出格式调整

  1. 转为字符串

    • str():函数返回一个用户易读的表达形式;
    • repr():产生一个解释器易读的表达形式;
  2. zfill( )

    • 该函数会在数字的左边填充 0;
  3. str.format()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # 1. 参数替换
    print('{}网址: "{}!"'.format('AngFff''www.angfff.top'))
    # 输出: AngFff网址: "www.angfff.top!"

    # 2. 数字标明位置
    print('{0} 和 {1}'.format('Google''Apple'))
    # 输出:Google 和 Apple

    # 3. 关键字指定参数
    print('{name}网址:{site}'.format(name='AngFff', site='123'))
    # AngFff网址:123

    # 4. 可选项,进一步控制格式
    # 将 Pi 保留到小数点后三位
    import math
    print('常量 PI 的值近似为 {0:.3f}。'.format(math.pi))
    # 输出:常量 PI 的值近似为 3.142。

    # 5. 控制宽度
    table = {'Google'1'Runoob'2'Taobao'3}
    for name, number in table.items():
    print('{0:10} ==> {1:10d}'.format(name, number))
    # 输出:
    # Google     ==>          1
    # Runoob     ==>          2
    # Taobao     ==>          3
    • 括号及其里面的字符 (称作格式化字段) 将会被 format() 中的参数替换;
    • 在括号中的数字用于指向传入对象在 format() 中的位置;
    • 如果在 format() 中使用了关键字参数, 那么它们的值会指向使用该名字的参数,位置及关键字参数可以任意的结合;
    • !a (使用 ascii()),  !s (使用 str()) 和  !r (使用 repr()) 可以用于在格式化某个值之前对其进行转化;
    • 可选项 : 和格式标识符可以跟着字段名,允许对值进行更好的格式化;
    • 在 : 后传入一个整数, 可以保证该域至少有这么多的宽度;

1.5 输入

1.5.1 标准输入

  1. input( ) 内置函数 从标准输入读入一行文本

    1
    2
    str = input("请输入:")
    print("输入内容为:", str)

1.5.2 文件读写

  1. 创建文件对象

    • open() 将会返回一个 file 对象 open(filename, mode)
    • filename:要打开的文件名
    • mode:决定了打开文件的模式,只读 ‘r’,写入 ‘w’,追加 ‘a’ 等。该参数是非强制的,默认文件访问模式为只读 ‘r’
    • 每次打开文件后,都需要关闭文件对象,调用 f.close()

    Python文件读写模式.png

  2. 针对文件对象进行读取

    • 在已创建 文件对象 的情况下 f = open()
    • f.read()
      • 调用 f.read(size),将读取一定数目的数据,然后作为字符串或字节对象返回
      • size 是一个可选的数字类型的参数,当 size 为空或者负,则该文件的所有内容都将被读取并且返回
    • f.readline()
      • f.readline() 会从文件中读取单独的一行,换行符为 ‘\n’
      • 如果返回一个空字符串,说明已经已经读取到最后一行
    • f.readlines()
      • f.readlines() 将返回该文件中包含的所有行
      • 如果设置可选参数 sizehint,则读取指定长度的字节,并且将这些字节按行分割
  3. 针对文件对象进行写入

    • 在已创建 文件对象 的情况下 f = open()
    • f.write()
      • f.write(string) 将 string 写入到文件中,然后返回写入的字符数
    • f.tell()
      • f.tell() 用于返回文件当前的读/写位置(即文件指针的位置)
      • 文件指针表示从文件开头开始的字节数偏移量
    • f.seek()
      • 要改变文件指针的位置,可以用 f.seek(offset, whence)
      • offset 表示相对于 whence 参数的偏移量,whence 如果是 0 表示开头,如果是 1 表示当前位置, 2 表示文件的结尾
        • seek(x,0):从起始位置即文件首行首字符开始移动 x 个字
        • seek(x,1):表示从当前位置往后移动 x 个字符
        • seek(-x,2):表示从文件的结尾往前移动 x 个字符
  4. 关闭文件

    • 在已创建 文件对象 的情况下 f = open()
    • f.close()
      • 调用 f.close() 来关闭文件并释放系统的资源
    • with 关键字用于简化文件操作并确保文件在使用完后自动关闭,避免手动调用 close() 方法。它会在代码块执行结束后自动管理资源的释放,即使代码中发生异常,也能保证文件被正确关闭
      1
      2
      3
      with open('/test.txt','r') as f:
      read_data = f.read()
      # 运行结束后,会自动关闭 f 对象,释放资源

1.6 运算符

  1. 算数运算符

    运算符描述
    +加 - 两个对象相加
    -减 - 得到负数或是一个数减去另一个数
    *乘 - 两个数相乘或是返回一个被重复若干次的字符串
    /除 - x 除以 y
    %取模 - 返回除法的余数
    **幂 - 返回x的y次幂
    //取整除 - 向下 / 左取整
  2. 比较(关系)运算符

    运算符描述
    ==等于 - 比较对象是否相等
    !=不等于 - 比较两个对象是否不相等
    >大于 - 返回x是否大于y
    <小于 - 返回x是否小于y
    >=大于等于 - 返回x是否大于等于y
    <=小于等于 - 返回x是否小于等于y
  3. 赋值运算符

    运算符描述
    =简单的赋值运算符
    +=加法赋值运算符
    -=减法赋值运算符
    *=乘法赋值运算符
    /=除法赋值运算符
    %=取模赋值运算符
    **=幂赋值运算符
    //=取整除赋值运算符
    :=海象运算符,这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。Python3.8 版本新增运算符
  4. 位运算符

    运算符描述实例(a=12 / b=13)
    &按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0(a & b) 输出结果 12 ,二进制解释: 0000 1100
    |按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。(a | b) 输出结果 61 ,二进制解释: 0011 1101
    ^按位异或运算符:当两对应的二进位相异时,结果为1(a ^ b) 输出结果 49 ,二进制解释: 0011 0001
    ~按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1。~x 类似于 -x-1(~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。
    <<左移动运算符:运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。a << 2 输出结果 240 ,二进制解释: 1111 0000
    >>右移动运算符:把">>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数a >> 2 输出结果 15 ,二进制解释: 0000 1111
  5. 逻辑运算符

    运算符逻辑表达式描述
    andx and y布尔"与" - 如果 x 为 False,x and y 返回 x 的值,否则返回 y 的计算值。
    orx or y布尔"或" - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。
    notnot x布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。
  6. 成员运算符

    运算符描述
    in如果在指定的序列中找到值返回 True,否则返回 False。
    not in如果在指定的序列中没有找到值返回 True,否则返回 False。
  7. 身份运算符

    运算符描述
    isis 是判断两个标识符是不是引用自一个对象
    is notis not 是判断两个标识符是不是引用自不同对象

2. 基本数据类型

2.1 数字(Number)

  1. int (整数)
    • 只有一种整数类型 int,表示为长整型,没有 Long
  2. bool (布尔)
    • bool 是 int 的子类,True / 1 和 False / 0 可以和数字相加
  3. float (浮点数)
    • 如 1.23、3E-2
  4. complex (复数)
    • 如 1 + 2j、 1.1 + 2.2j
函数返回值 ( 描述 )
abs(x)返回数字的绝对值,如abs(-10) 返回 10
ceil(x)返回数字的上入整数,如math.ceil(4.1) 返回 5
cmp(x, y)如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1。 Python 3 已废弃,使用 (x>y)-(x<y) 替换
exp(x)返回e的x次幂(ex),如math.exp(1) 返回2.718281828459045
fabs(x)以浮点数形式返回数字的绝对值,如math.fabs(-10) 返回10.0
floor(x)返回数字的下舍整数,如math.floor(4.9)返回 4
log(x)如math.log(math.e)返回1.0,math.log(100,10)返回2.0
log10(x)返回以10为基数的x的对数,如math.log10(100)返回 2.0
max(x1, x2,…)返回给定参数的最大值,参数可以为序列。
min(x1, x2,…)返回给定参数的最小值,参数可以为序列。
modf(x)返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示。
pow(x, y)x**y 运算后的值。
round(x [,n])返回浮点数 x 的四舍五入值,如给出 n 值,则代表舍入到小数点后的位数。

其实准确的说是保留值将保留到离上一位更近的一端。
sqrt(x)返回数字x的平方根。

2.2 字符串(String)

  1. 字符串用单引号 ’ 或双引号 " 括起来,单引号 ’ 和双引号 " 的使用完全相同,使用三引号(‘’’ 或 “”")可以指定一个多行字符串;
  2. 使用反斜杠 \ 转义特殊字符,使用 r 可以让反斜杠不发生转义。 如 r"this is a line with \n" 则 \n 会显示,并不是换行;
  3. 字符串的截取 / 切片
    • 字符串[start:end:step],左含右不含、步长参数 step,step 为负数时表示逆向;
    • 索引值以 0 为开始值,-1 为从末尾的开始位置;
    • 加号 + 是字符串的连接符, 星号 * 表示复制当前字符串;
  4. Python 没有单独的字符类型,一个字符就是长度为 1 的字符串;
  5. 字符串不能通过索引赋值、修改元素值;

2.3 布尔(Bool)

  1. 布尔类型只有两个值:True 和 False,等价于 1 和 0;
  2. 布尔类型可以转换成其他数据类型;
  3. 使用 bool() 函数将其他类型的值转换为布尔值;
  4. 布尔类型可以和逻辑运算符一起使用,包括 and、or 和 not;

2.4 列表(List)

  1. 列表写在方括号 [] 之间、用逗号分隔元素;
  2. 列表中的元素类型可以互不相同;
  3. 列表可以通过索引赋值、修改元素值;
  4. 列表的截取 / 切片
    • 列表[start:end:step],左含右不含、步长参数 step,step 为负数时表示逆向;
    • 索引值以 0 为开始值,-1 为从末尾的开始位置;
    • 加号 + 是列表的连接符, 星号 * 表示复制当前列表;

2.5 元组(Tuple)

  1. 元组写在小括号 () 之间、用逗号分隔元素;
  2. 元组中的元素类型可以互不相同;
  3. 元组不能通过索引赋值、修改元素值;
  4. 元组的截取 / 切片
    • 元组[start:end:step],左含右不含、步长参数 step,step 为负数时表示逆向;
    • 索引值以 0 为开始值,-1 为从末尾的开始位置;
    • 加号 + 是元组的连接符, 星号 * 表示复制当前元组;
  5. 构造包含 0 个或 1 个元素的元组比较特殊
    1
    2
    tup1 = () # 空元组
    tup2 = (20,) # 一个元素,需要在元素后添加逗号

2.6 集合(Set)

  1. 集合写在大括号 {} 之间、用逗号分隔元素,另外也可以使用 set() 函数创建集合;
  2. 创建一个空集合必须用 set() 而不是 { }, { } 用于创建空字典;
  3. 集合是一种无序、可变的数据类型,其中的元素不会重复;
  4. 集合运算
    • 交集 &
    • 并集 |
    • 差集 -
    • 两集合中不同时存在的元素 ^

2.7 字典(Dictionary)

  1. 字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合;
  2. 在同一个字典中,键必须是唯一的,且键必须使用不可变类型;
  3. 字典的创建
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    dict1 = {}
    dict1['one'] = "1 A"
    dict1[2] = "2 F"

    dict2 = {'name': 'Ang', 'age': '18'}

    # 字典推导式
    dict3 = {x: x**2 for x in (246)}

    x = ['A','B','C','D']
    y = ['a','b','c','d']
    dict4 = {i:j for i,j in zip(x,y)}

    # dict 函数
    dict5 = dict(Runoob=1, Google=2, Taobao=3)
  4. 键值对输出
    1
    2
    3
    4
    dic1 = {'a': 1, 'b': 2, 'c': 3}
    # 输出
    for k,v. in dict1.items():
    print(k, ':', v)

3. 基本数据类型的转换

3.1 隐式类型转换

  1. 对两种不同类型的数据进行运算时,较低数据类型会转换为较高数据类型以避免数据丢失;
    • 当整数与浮点数进行运算时,整数会被自动转换为浮点数;
    • 布尔值在与数字进行运算时会被自动转换为整数,True 被视为 1False 被视为 0
  2. 数据类型的高低:bool < int < float < complex

3.2 显式类型转换

函数描述
int(x [,base])将x转换为一个整数
float(x)将x转换到一个浮点数
complex(real [,imag])创建一个复数
str(x)将对象 x 转换为字符串
repr(x)将对象 x 转换为表达式字符串
eval(str)用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s)将序列 s 转换为一个元组
list(s)将序列 s 转换为一个列表
set(s)转换为可变集合
dict(d)创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s)转换为不可变集合
chr(x)将一个整数转换为一个字符
ord(x)将一个字符转换为它的整数值
hex(x)将一个整数转换为一个十六进制字符串
oct(x)将一个整数转换为一个八进制字符串

4. 条件控制

4.1 if-elif-else

1
2
3
4
5
6
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3
  • 每个条件后面要使用冒号,表示接下来是满足条件后要执行的语句块。
  • 如果 if 的执行语句只有一句,可以写在 if 的同一行。

4.2 match-case

1
2
3
4
5
6
7
8
9
match subject:
case <pattern_1>:
<action_1>
case <pattern_2>:
<action_2>
case <pattern_3>:
<action_3>
case _:
<action_wildcard>
  • case _: 类似于 C 和 Java 中的 default:,当其他 case 都无法匹配时,匹配这条,保证永远会匹配成功。

5. 循环语句

5.1 while

1
2
3
4
while <expr>:
<statement(s)>
else:
<additional_statement(s)>
  • 如果 while 的执行语句只有一句,可以写在 while 的同一行。

5.2 for

1
2
3
4
for item in iterable:
# 循环主体
else:
# 循环结束后执行的代码

5.3 break & continue & pass

  • break 语句可以跳出 for 和 while 的循环体。如果你从 for 或 while 循环中终止,任何对应的循环 else 块将不执行。
  • continue 语句被用来告诉 Python 跳过当前循环块中的剩余语句,然后继续进行下一轮循环。
  • pass 不做任何事情,一般用做占位语句。

6. 推导式

6.1 列表推导式

1
2
3
4
5
[表达式 for 变量 in 列表]

或者

[表达式 for 变量 in 列表 if 条件]

e.g. 过滤掉长度小于或等于3的字符串列表,并将剩下的转换成大写字母

1
2
3
names = ['Bob','Tom','alice','Jerry','Wendy','Smith']
new_names = [name.upper()for name in names if len(name)>3]
print(new_names)

6.2 字典推导式

1
2
3
4
5
{ key_expr: value_expr for value in collection }



{ key_expr: value_expr for value in collection if condition }

e.g. 将列表中各字符串值为键,各字符串的长度为值,组成键值对

1
2
3
listdemo = ['Google','Runoob', 'Taobao']
newdict = {key:len(key) for key in listdemo}
print(newdict)

6.3 集合推导式

1
2
3
{ expression for item in Sequence }

{ expression for item in Sequence if conditional }

e.g. 判断不是 abc 的字母并输出

1
2
a = {x for x in 'abracadabra' if x not in 'abc'}
print(a)

6.4 元组推导式

1
2
3
(expression for item in Sequence )

(expression for item in Sequence if conditional )
  • 元组推导式返回的结果是一个生成器对象,使用 tuple() 函数,可以直接将生成器对象转换成元组;

e.g. 生成一个包含数字 1~9 的元组

1
2
3
4
5
6
t = (x for x in range(1, 10))
print(t) # 输出 <generator object <genexpr> at 0x104b0e890>
print(tuple(t)) # 输出 (1, 2, 3, 4, 5, 6, 7, 8, 9)

# range() 返回的是一个可迭代对象,而不是一个列表
# 如果需要列表,可以使用 list() 函数将其转换

7. 迭代器 & 生成器

7.1 迭代器

(1)概念

在 Python 中,迭代器(Iterator)是一种用于遍历集合(如列表、元组、字典等)元素的对象。迭代器遵循迭代协议,主要包括两个方法:__iter__()__next__()。下面是对迭代器的详细解释:

  1. 迭代器的基本概念
  • 迭代器对象:实现了 __iter__()__next__() 方法的对象。
  • 可迭代对象:实现了 __iter__() 方法的对象,可以返回一个迭代器。
  1. 迭代器的工作原理
  • __iter__() 方法:返回迭代器对象本身。通常在可迭代对象上调用时会返回一个迭代器。
  • __next__() 方法:返回序列中的下一个值。如果没有更多的值可返回,应该抛出 StopIteration 异常。

(2)从集合生成迭代器

  • 可迭代对象:可以使用 for 循环遍历的对象,如列表、元组、字典、集合等。可迭代对象实现了 __iter__() 方法。
  • 基本方法:iter();next()

e.g. 从列表生成迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 原列表
list_a = [1, 2, 3, 4]

# 迭代器对象
it = iter(list_a)

# 输出单个元素,使用 next() 方法
print(next(it))

# 循环输出剩余元素,使用 for/while 循环
for i in it:
print(i, end=" ")

# while 循环注意结束条件
while True:
try:
print(next(it))
except StopIteration:
sys.exit()

(3)创建自定义迭代器

  • 通过定义一个类并实现 _iter_\ 和 _next_\ 两个方法来创建自定义迭代器。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建迭代器
class MyIterator:
def __init__(self, max):
self.max = max
self.current = 0

def __iter__(self):
return self

def __next__(self):
if self.current < self.max:
result = self.current
self.current += 1
return result
else:
raise StopIteration

# 使用自定义迭代器
my_iter = MyIterator(5)
for num in my_iter:
print(num) # 输出 0 1 2 3 4

(4)迭代器与可迭代对象的区别

  • 可迭代对象:可以使用 for 循环遍历的对象,如列表、元组、字典、集合等。可迭代对象实现了 __iter__() 方法。
  • 迭代器:是可迭代对象的一个实现,具有 __iter__()__next__() 方法。迭代器可以在遍历时保持状态。

7.2 生成器

(1)概念

在 Python 中,生成器(Generator)是一种特殊类型的迭代器,用于创建可迭代的序列。生成器的主要特点是它们使用 yield 语句来返回值,而不是使用 return 语句。生成器在每次调用时会记住上一次的状态,从而实现惰性求值。

  • 生成器函数:使用 yield 语句定义的函数。调用生成器函数不会立即执行,而是返回一个生成器对象。
  • 生成器对象:可以被迭代的对象,支持 __iter__()__next__() 方法。

(2)创建生成器

  • 生成器函数的定义与普通函数类似,但使用 yield 语句来返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys

# 生成器函数 - 斐波那契
def fibonacci(n):
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a # 当运行到这里时,就会停止,直到再次调用 next,会接着从这里继续生成 a
a, b = b, a + b
counter += 1

# f 是一个迭代器,由生成器返回生成
f = fibonacci(10)

# 输出值
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()

(3)生成器的工作原理

  • 当调用生成器函数时,函数体不会立即执行,而是返回一个生成器对象。
  • 每次调用生成器对象的 __next__() 方法时,函数会从上次 yield 语句停止的地方继续执行,直到遇到下一个 yield 语句。
  • 当没有更多的 yield 语句可执行时,生成器会抛出 StopIteration 异常,表示迭代结束。

8. 函数

8.1 定义 / 调用函数

1
2
3
4
5
6
7
8
# 定义函数
def 函数名(参数列表):
# 函数说明
函数体
return

# 调用函数
返回值 = 函数名(参数)

python 函数的参数传递:

  • 不可变类型:类似 C++ 的值传递,不可变类型对象包括 整数、字符串、元组。对于不可变类型对象 a,调用 fun(a) 时,传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象,函数外部的 a 不会受影响。

  • 可变类型:类似 C++ 的引用传递,可变类型对象包括 列表,字典。对于可变类型对象 b,调用 fun(b) 时,则是将 b 真正的传过去,修改后 fun 外部的 b 也会受影响。

8.2 函数参数

(1)必需参数

  • 必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样,否则会因缺少参数而报错。

(2)关键字参数

  • 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
  • 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

e.g.

1
2
3
4
5
6
7
8
9
# 可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return

# 调用printinfo函数
printinfo( age=50, name="runoob" )

(3)默认参数

  • 调用函数时,如果没有传递参数,则会使用默认参数

(4)不定长参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 一个 * 的参数会以元组形式导入
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]

# 两个 * 的参数会以字典形式导入
def printinfo( arg1, **vardict ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vardict)

# 单独出现 *,则 * 以后的所有参数都需要带上参数名称再传入
# 函数定义
def f(a,b,*,c):
return a+b+c
# 函数调用
f(1,2,c=3)

# 强制位置参数 /
# 函数定义
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
# 函数调用
f(10, 20, 30, d=40, e=50, f=60)

# 形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 和 f 要求为关键字形参
  • 加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数
  • 可以不向函数传递未命名的变量,如果在函数调用时没有指定参数,它就是一个空元组
  • 加了两个星号 ** 的参数会以字典的形式导入
  • 如果单独出现星号 * ,则星号 * 后的参数必须用关键字传入
  • 强制位置参数:Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。

8.3 lambda 匿名函数

(1)概念

在 Python 中,lambda 函数是一种小型、匿名的、内联函数,它可以具有任意数量的参数,但只能有一个表达式。与常规的函数定义(使用 def 关键字)相比,lambda 函数通常用于需要快速定义简单函数的场景。

lambda 函数的基本语法如下:

1
lambda arguments: expression
  • arguments: 输入参数,可以是多个,用逗号分隔。
  • expression: 一个表达式,返回值是这个表达式的计算结果。

② 示例

1
2
3
4
5
6
# 创建一个简单的 lambda 函数
add = lambda x, y: x + y

# 使用 lambda 函数
result = add(3, 5)
print(result) # 输出: 8

(2)应用(使用 lambda 函数作为参数)

lambda 函数常用于需要函数作为参数的场景,例如在 map(), filter(), 和 sorted() 函数中。
map()

  • map() 函数用于将指定函数应用于给定可迭代对象的每个元素,并返回一个迭代器
    • map(function, iterable)
    • function: 要应用的函数(可以是 lambda 函数)
    • iterable: 要处理的可迭代对象(如列表、元组等)
  • 示例
1
2
3
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers)) # map 会遍历 numbers 中的每个元素,并将每个元素传递给 lambda 函数,计算完成后作为 map 迭代器的结果,需要时输出
print(squared) # 输出: [1, 4, 9, 16, 25]

filter()

  • filter() 函数用于过滤可迭代对象中的元素,返回满足条件的元素
    • filter(function, iterable)
    • 遍历每个元素,如果满足 function 中的条件(返回 True),则保留该元素;否则,丢弃该元素
  • 示例
1
2
3
numbers = [1, 2, 3, 4, 5]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) # filter 会遍历 numbers 中的每个元素,并将每个元素传递给 lambda 函数,判断元素是否为偶数,是偶数则保留,否则丢弃该元素
print(even_numbers) # 输出: [2, 4]

sorted()

  • sorted() 函数用于对可迭代对象进行排序,可以使用 lambda 函数自定义排序规则。
    • sorted(iterable, key=None, reverse=False)
    • key 是一个函数,用于从每个元素中提取比较键
    • 默认升序排列,reverse=True,则调整为降序
  • 示例
1
2
3
points = [(1, 2), (3, 1), (5, 0), (0, 3)]
sorted_points = sorted(points, key=lambda point: point[1]) # sorted 会遍历 points 中的每个元组,并将每个元组传递给 lambda 函数,lambda 会提取每个元组的第二个元素(y 坐标)作为排序的依据,最终按 key(y坐标)排序
print(sorted_points) # 输出: [(5, 0), (3, 1), (1, 2), (0, 3)]

(3)注意

  • 单行表达式lambda 函数只能包含一个表达式,不能包含多个语句或复杂的逻辑。
  • 可读性:虽然 lambda 函数可以使代码更简洁,但在复杂的情况下,使用常规的 def 函数可能会提高代码的可读性。
  • 命名lambda 函数是匿名的,但可以赋值给变量以便后续使用。

9. 装饰器

9.1 概念

(1)定义

在 Python 中,装饰器(decorator)是一种用于修改或增强函数或方法行为的设计模式。装饰器本质上是一个函数,它接受另一个函数作为参数,并返回一个新的函数。通过使用装饰器,可以在不修改原始函数代码的情况下,添加额外的功能或行为。

(2)常见用途

  • 日志记录:记录函数的调用信息。
  • 权限检查:在执行函数之前检查用户权限。
  • 缓存:缓存函数的返回值以提高性能。
  • 输入验证:验证函数参数的有效性。

9.2 装饰器的基本语法

  • 装饰器通常使用 @decorator_name 语法来应用,放在被装饰函数的定义上方
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义 装饰器
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper

# 应用 装饰器
@my_decorator
def say_hello():
print("Hello!")

say_hello() # 输出三行句子

9.3 带参数的装饰器

  • 装饰器也可以接受参数。为了实现这一点,通常需要在最外层再嵌套一层函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 定义 含参数的装饰器
def repeat(num_times):
# 最外层用于定义参数
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat

# 应用 装饰器
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")

greet("Alice") # 重复输出三次 Hello, Alice!

10. 数据结构

10.1 将列表当作栈使用

  • 在 Python 中,可以使用列表(list)来实现栈的功能。栈是一种后进先出(LIFO, Last-In-First-Out)数据结构,意味着最后添加的元素最先被移除。
  • 用 append() 方法可以把一个元素添加到栈顶,用不指定索引的 pop() 方法可以把一个元素从栈顶释放出来。
  • 压入(Push): 将一个元素添加到栈的顶端。
  • 弹出(Pop): 移除并返回栈顶元素。
  • 查看栈顶元素(Peek/Top): 返回栈顶元素而不移除它。
  • 检查是否为空(IsEmpty): 检查栈是否为空。
  • 获取栈的大小(Size): 获取栈中元素的数量。

1、创建一个空栈

1
stack = []  

2、压入(Push)操作

  • 使用 append() 方法将元素添加到栈的顶端
1
2
3
4
stack.append(1)  
stack.append(2)
stack.append(3)
print(stack)  # 输出: [1, 2, 3]

3、弹出(Pop)操作

  • 使用 pop() 方法移除并返回栈顶元素
1
2
3
top_element = stack.pop()  
print(top_element)  # 输出: 3
print(stack)        # 输出: [1, 2]

4、查看栈顶元素(Peek/Top)

  • 直接访问列表的最后一个元素(不移除)
1
2
top_element = stack[-1]  
print(top_element)  # 输出: 2

5、检查是否为空(IsEmpty)

  • 检查列表是否为空
1
2
is_empty = len(stack) == 0  
print(is_empty)  # 输出: False

6、获取栈的大小(Size)

  • 使用 len() 函数获取栈中元素的数量
1
2
size = len(stack)  
print(size)  # 输出: 2

10.2 将列表当作队列使用

  • 在 Python 中,列表(list)可以用作队列(queue),但由于列表的特点,直接使用列表来实现队列并不是最优的选择。
  • 队列是一种先进先出(FIFO, First-In-First-Out)的数据结构,意味着最早添加的元素最先被移除。
  • 使用列表时,如果频繁地在列表的开头插入或删除元素,性能会受到影响,因为这些操作的时间复杂度是 O(n)。为了解决这个问题,Python 提供了 collections.deque,它是双端队列,可以在两端高效地添加和删除元素。
  • collections.deque 是 Python 标准库的一部分,非常适合用于实现队列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from collections import deque  

# 创建一个空队列
queue = deque()

# 向队尾添加元素
queue.append('a')
queue.append('b')
queue.append('c')

print("队列状态:", queue)  # 输出: 队列状态: deque(['a', 'b', 'c'])

# 从队首移除元素
first_element = queue.popleft()
print("移除的元素:", first_element)  # 输出: 移除的元素: a
print("队列状态:", queue)            # 输出: 队列状态: deque(['b', 'c'])

# 查看队首元素(不移除)
front_element = queue[0]
print("队首元素:", front_element)    # 输出: 队首元素: b

# 检查队列是否为空
is_empty = len(queue) == 0
print("队列是否为空:", is_empty)     # 输出: 队列是否为空: False

# 获取队列大小
size = len(queue)
print("队列大小:", size)            # 输出: 队列大小: 2
  • 虽然 deque更高效,但如果坚持使用列表来实现队列,也可以这么做。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. 创建队列
queue = []

# 2. 向队尾添加元素,使用 append() 方法将元素添加到队尾
queue.append('a')
queue.append('b')
queue.append('c')
print("队列状态:", queue)  # 输出: 队列状态: ['a', 'b', 'c']

# 3. 从队首移除元素,使用 pop(0) 方法从队首移除元素
first_element = queue.pop(0)
print("移除的元素:", first_element)  # 输出: 移除的元素: a
print("队列状态:", queue)            # 输出: 队列状态: ['b', 'c']

# 4. 查看队首元素,直接访问列表的第一个元素
front_element = queue[0]
print("队首元素:", front_element)    # 输出: 队首元素: b

# 5. 检查队列是否为空
is_empty = len(queue) == 0
print("队列是否为空:", is_empty)     # 输出: 队列是否为空: False

# 6. 获取队列大小,使用 len() 函数获取队列的大小
size = len(queue)
print("队列大小:", size)            # 输出: 队列大小: 2