skip to content
Logo Lostman_Wang的小站

Python函数-匿名函数、生成器、内置函数和推导式

一、匿名函数

1、定义

  • lambda 参数列表: 单表达式 会即时返回一个函数对象,没有名字,通常作为一次性、短小逻辑的“即用即弃”函数。

2、基本语法

位置写法举例说明
无参lambda: 42直接返回 42
单参lambda x: x*2输入乘以 2
多参lambda x, y, z=10: x+y+z支持默认参数
可变参lambda *a, **kw: len(a)+len(kw)支持 *args、**kwargs

注意:

  • 只能有一个表达式,不能出现赋值、for、if-else 语句(三元表达式可以)。
  • 返回值就是表达式的值,无需return

3、作用域规则(与 def 完全一致)

  • 遵循 LEGB;
  • 同样形成闭包:
fs = [lambda x: x + i for i in range(3)]
print([f(0) for f in fs]) # [2, 2, 2]
# 这里 i=i 把循环变量冻结到默认参数,避免“延迟绑定陷阱”。
fs = [lambda x, i=i: x + i for i in range(3)]
print([f(0) for f in fs]) # [0, 1, 2]

lambda 闭包的语法就是:

lambda 形参1, 形参2=默认值 : 表达式
  • 只要表达式里出现外层局部变量,就形成闭包;
  • 在循环里务必用“默认参数”把值钉死,否则所有匿名函数共享同一个变量。

4、与 def 的对比

维度lambdadef
名称匿名必须显式命名
主体单表达式多语句块
结果隐式 return可显式 return
可读性极短逻辑长逻辑更清晰
调试栈跟踪显示 <lambda>显示函数名
注解无法直接写注解支持完整的函数签名

5、常见误区

5.1、“lambda 比 def 快”

  • 执行速度几乎一样;lambda 只是省去了栈帧名字绑定。

5.2、循环变量陷阱

fs = [lambda: i for i in range(3)]
print([f() for f in fs]) # [2, 2, 2]
# 解决:用默认参数或改用 def。

5.3、试图写多行

lambda x: y = x*2; return y # SyntaxError
# 长逻辑请用 def。

6、进阶技巧

  • 立即调用:(lambda x: x**2)(5)
  • 与高阶函数搭配:mapfiltersortedkey 参数
  • 柯里化:
from functools import partial
mul = lambda x, y: x * y
double = partial(mul, 2)

7、典型场景

7.1、sorted 的 key 函数

sorted(students, key=lambda s: s.score, reverse=True)

7.2、GUI 回调 / CLI 框架

button.clicked.connect(lambda: print('clicked'))

7.3、小脚本中的过滤

evens = list(filter(lambda n: n % 2 == 0, range(10)))

二、三元运算符

1、语法结构

value_if_true if condition else value_if_false
  • condition:一个布尔表达式,其结果为 True 或 False。
  • value_if_true:如果 condition 为 True,则返回这个值。
  • value_if_false:如果 condition 为 False,则返回这个值。

2、基本用法

x = 10
y = 20
# 使用三元运算符
result = x if x > y else y
print(result) # 输出 20
  • 在这个例子中,x > y 是条件。因为 x 不大于 y,所以条件为 False,返回 y

3、更复杂的表达式

a = 5
b = 10
# 使用三元运算符嵌套
result = "Both are equal" if a == b else "a is greater" if a > b else "b is greater"
print(result) # 输出 "b is greater"

4、与传统 if-else 的对比

4.1、传统 if-else

x = 10
y = 20
if x > y:
result = x
else:
result = y
print(result) # 输出 20

4.2、三元运算符

x = 10
y = 20
result = x if x > y else y
print(result) # 输出 20
  • 三元运算符在表达简单逻辑时更加简洁,但当逻辑复杂时,建议使用传统的 if-else 结构,以提高代码的可读性。

5、注意事项

  1. 可读性:虽然三元运算符很简洁,但嵌套使用时可能会降低代码的可读性。尽量避免过度嵌套。
  2. 短路行为:三元运算符具有短路行为。如果条件为 True,则不会计算 value_if_false;如果条件为 False,则不会计算 value_if_true
  3. 类型一致性:虽然 Python 允许 value_if_truevalue_if_false 是不同类型,但为了代码的可读性和一致性,建议它们是相同类型。

6、实际应用场景

6.1、设置默认值

user_input = input("Enter a number: ")
number = int(user_input) if user_input.isdigit() else 0
print(number) # 如果输入不是数字,默认为 0

6.2、简化逻辑

# 传统写法
if condition:
result = value1
else:
result = value2
# 三元写法
result = value1 if condition else value2

6.3、条件赋值

# 根据条件选择字符串
message = "Success" if status_code == 200 else "Error"

三、生成器(Generator)

1、定义

  • 生成器是一种可迭代对象,它逐个生成值,而不是一次性返回所有值。生成器函数通过 yield 关键字返回一个生成器对象。

2、生成器的核心特点

  • 惰性求值:值在需要时才生成
  • 内存高效:不需要存储整个序列在内存中
  • 可恢复状态:每次调用从上次暂停处继续执行
  • 无限序列:可以表示无限长的数据流

3、创建生成器的两种方式

3.1、生成器函数

  • 使用 def 定义函数,并在函数体内使用 yield 语句
def count_up_to(max):
count = 1
while count <= max:
yield count
count += 1
gen = count_up_to(100)
print(gen)
输出:<generator object count_up_to at 0x7f24ef254890>

3.2、生成器表达式

  • 类似列表推导式,但使用圆括号 ()
squares = (x*x for x in range(10))

4、生成器的工作流程(图示)

调用生成器函数
创建生成器对象 ────────────────┐
│ │
▼ │
首次调用 next() │
│ │
▼ │
执行到第一个 yield 暂停 ◄──────┤
│ 返回 yield 的值 │
▼ │
后续调用 next() │
│ │
▼ │
从上个 yield 后继续执行 ◄──────┘
遇到 return 或函数结束
抛出 StopIteration 异常

5、生成器函数 vs 普通函数

特性普通函数生成器函数
返回值使用 return使用 yield
执行方式一次执行完成可暂停和恢复
返回值单次返回值可多次返回值
状态每次调用独立保持上次执行状态
内存使用可能占用大量内存内存高效

6、生成器的内存模型(图示)

普通列表的内存使用:
┌──────────────┐
│ 列表对象 │
│ │
│ [0,1,4,9,16] │ 存储所有元素
└──────────────┘
└─ 占用连续内存块
生成器的内存使用:
┌──────────────┐ 按需生成值
│ 生成器对象 │ ┌───┐ ┌───┐ ┌───┐
│ 状态: count=3 │───▶│ 0 │▶│ 1 │▶│ 4 │ ...
│ 代码位置 │ └───┘ └───┘ └───┘
└──────────────┘ 每次只保留
当前状态和代码位置

7、生成器的生命周期(代码演示)

def number_generator(n):
print("生成器启动")
for i in range(n):
print(f"即将生成 {i}")
yield i
print(f"恢复执行")
print("生成器结束")
# 创建生成器
gen = number_generator(3)
# 逐步执行
print("第一次调用:")
print(next(gen)) # 输出: 生成器启动, 即将生成 0, 0
print("\n第二次调用:")
print(next(gen)) # 输出: 恢复执行, 即将生成 1, 1
print("\n第三次调用:")
print(next(gen)) # 输出: 恢复执行, 即将生成 2, 2
print("\n第四次调用:")
try:
print(next(gen)) # 输出: 恢复执行, 生成器结束
except StopIteration:
print("生成器已耗尽")

8、生成器next()for 循环取值比较

8.1、一段最小生成器

def func():
yield 1
yield 2
yield 3

8.2、三种拿值方式对比

方式语法得到 StopIteration 时的行为常见场景
next()next(gen)抛出 StopIteration手动驱动,一次拿一个
for 循环for x in gen:自动捕获并结束循环遍历整个序列
列表/集合推导式[x for x in gen]自动捕获并结束推导一次性收集

8.3、运行流程逐帧图

生成器代码 外部代码 返回值
─────────────────────────
yield 1 ←─ next() ── 1
yield 2 ←─ next() ── 2
yield 3 ←─ next() ── 3
函数结束 → StopIteration 异常
  • for 循环 把“异常→结束”这一步隐藏掉了,所以用户无感。
  • 每次 next()for 循环的迭代都会让生成器从上次 yield 处继续往下跑。

8.4、代码示例:三种写法效果相同

gen = func()
# 1) 手动 next()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
try:
next(gen) # StopIteration
except StopIteration:
print("结束")
# 2) for 循环
gen = func()
for x in gen:
print(x) # 1 2 3
# 3) 列表推导式
gen = func()
lst = [x for x in gen]
print(lst) # [1, 2, 3]

8.5、一句话总结

  • next(gen) 是“手摇发动机”,每转一圈拿一个值;
  • for 循环是“自动发动机”,直到油尽(StopIteration)为止;
  • 两者背后都是同一条 yield 管道,只是谁负责关掉水龙头。

9、注意事项

  1. 生成器是一次性对象,遍历后不能重用
  2. 使用 yield 后函数返回生成器对象,不立即执行
  3. 需要手动调用 next() 或使用循环启动生成器
  4. 生成器不存储所有值,不能随机访问

四、内置函数

abs()delattr()hash()memoryview()set()
all()dict()help()min()setattr()
any()dir()hex()next()slice()
ascii()divmod()id()object()sorted()
bin()enumerate()input()oct()staticmethod()
bool()eval()int()open()str()
breakpoint()exec()isinstance()ord()sum()
bytearray()filter()issubclass()pow()super()
bytes()float()iter()print()tuple()
callable()format()len()property()type()
chr()frozenset()list()range()vars()
classmethod()getattr()locals()repr()zip()
compile()globals()map()reversed()__import__()
complex()hasattr()max()round()
  1. abs(x):返回数字 x的绝对值。
  2. all(iterable):如果可迭代对象 iterable 中的所有元素都为真(truthy),则返回 True
  3. any(iterable):如果可迭代对象 iterable 中有任何元素为真(truthy),则返回 True
  4. ascii(obj):返回对象 obj 的可打印字符表示形式。
  5. bin(x):将整数 x 转换为二进制字符串。
  6. bool(x):将 x转换为布尔值,非零数值、非空序列等为 True,否则为 False
  7. bytearray(iterable):返回一个可变的字节数组,由 iterable 中的元素构成。
  8. bytes(iterable):返回一个不可变的字节序列,由 iterable 中的元素构成。
  9. callable(obj):如果 obj 是可调用对象(如函数、方法等),则返回 True
  10. chr(i):返回整数 i 对应的 Unicode 字符。
  11. classmethod(func):将函数 func 转换为类方法。
  12. compile(source, filename, mode):将源代码 source 编译成代码对象。
  13. complex(real, imag):创建一个复数,其实部为 real,虚部为 imag
  14. delattr(obj, name):删除对象 obj 的属性 name
  15. dict(**kwargs):创建并返回一个字典。
  16. dir():不带参数时,返回当前局部符号表的列表。带参数时,返回对象的属性列表。
  17. divmod(a, b):返回 a 除以 b 的商和余数。
  18. enumerate(iterable, start=0):返回一个枚举对象,它产生 (index, value) 对。
  19. eval(expression, globals=None, locals=None):计算字符串 expression 中的表达式,并返回结果。
  20. exec(object, globals=None, locals=None):执行动态生成的 Python 代码。
  21. filter(function, iterable):构造一个迭代器,返回使函数 function 返回值为真的那些元素。
  22. float(x):将 x 转换为浮点数。
  23. format(value, format_spec):将 value 格式化为字符串。
  24. frozenset(iterable):返回一个不可变的集合,由 iterable中的元素构成。
  25. getattr(object, name[, default]):返回对象 object的属性 name,如果没有该属性则返回 default
  26. globals():返回当前全局符号表的字典。
  27. hasattr(object, name):如果对象 object 有属性 name,则返回 True
  28. hash(object):返回对象 object 的哈希值。
  29. help(object):显示对象 object 的帮助信息。
  30. hex(x):将整数 x 转换为十六进制字符串。
  31. id(object):返回对象 object 的唯一标识符。
  32. input(prompt=''):显示提示信息 prompt 并返回用户输入的字符串。
  33. int(x[, base]):将 x 转换为整数,可选参数 base 指定进制。
  34. isinstance(object, classinfo):如果 objectclassinfo 的实例或其子类的实例,则返回 True
  35. issubclass(C, B):如果类 C 是类 B 的子类,则返回 True
  36. iter(iterable, sentinel):返回迭代器对象,可选参数 sentinel 指定迭代结束条件。
  37. len(object):返回对象 object 的长度。
  38. list(iterable):返回列表,由 iterable 中的元素构成。
  39. locals():返回当前局部符号表的字典。
  40. map(function, iterable, ...):将函数 function 应用于 iterable 中的每个元素,并返回结果的迭代器。
  41. max(iterable, *args, key=None, default=None):返回 iterable 中的最大值。
  42. memoryview(object):返回对象的内存视图。
  43. min(iterable, *args, key=None, default=None):返回 iterable 中的最小值。
  44. next(iterator[, default]):返回迭代器的下一个元素,如果没有更多元素则返回 default
  45. object():返回一个新的、未命名的对象。
  46. oct(x):将整数 x 转换为八进制字符串。
  47. open(file, mode='r', ...):打开文件并返回文件对象。
  48. ord(c):返回字符 c 的 Unicode 码点。
  49. pow(base, exp[, mod]):返回 baseexp 次幂,可选参数 mod 指定取模。
  50. print(*args, sep=' ', end='\n', file=sys.stdout, flush=False):打印 args 中的值,用 sep 分隔,以 end 结尾。
  51. property(fget=None, fset=None, fdel=None, doc=None):返回一个属性对象。
  52. range(start, stop[, step]):返回一个整数序列。
  53. repr(object):返回对象的“官方”字符串表示形式。
  54. reversed(seq):返回一个反向迭代器。
  55. round(number[, ndigits]):返回浮点数 number 四舍五入到小数点后 ndigits 位的值。
  56. set(iterable):返回一个集合,由 iterable 中的元素构成。
  57. setattr(object, name, value):设置对象 object 的属性 namevalue
  58. slice(stop):返回一个切片对象。
  59. sorted(iterable, *, key=None, reverse=False):返回 iterable 的排序列表。
  60. staticmethod(function):将函数 function 转换为静态方法。
  61. str(object='):将 object 转换为字符串。
  62. sum(iterable, start=0):返回 iterable 中元素的总和。
  63. super():返回一个代理对象,用于调用父类的方法。
  64. tuple(iterable):返回一个元组,由 iterable 中的元素构成。
  65. type(name, bases, dict):返回一个新的类型对象。
  66. vars(object):返回对象的 __dict__ 属性。
  67. zip(iter1, ..., iterN):将多个迭代器中对应的元素打包成一个个元组,然后返回由这些元组组成的迭代器。
  68. __import__(name, globals=None, locals=None, fromlist=(), level=0):动态导入模块。

五、推导式

  • Python 推导式(Comprehensions)是一种构建列表(list)、集合(set)、字典(dict)和生成器表达式(generator expressions)的简洁方式。推导式不仅代码更简洁,而且通常比等价的普通代码执行得更快,因为它们是专为迭代优化的。

1、列表推导式(List Comprehensions)

  • 列表推导式提供了一种从其他列表构建新列表的简便方式。

1.1、基本语法:

[expression for item in iterable if condition]

1.2、示例:

# 普通方式
squares = []
for i in range(10):
squares.append(i * i)
# 列表推导式
squares = [i * i for i in range(10)]
print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

2、集合推导式(Set Comprehensions)

  • 集合推导式与列表推导式类似,但它生成的是集合。

2.1、基本语法:

{expression for item in iterable if condition}

2.2、示例:

# 普通方式
unique_numbers = set()
for i in range(20):
unique_numbers.add(i % 5)
# 集合推导式
unique_numbers = {i % 5 for i in range(20)}
print(unique_numbers) # 输出: {0, 1, 2, 3, 4}

3、字典推导式(Dict Comprehensions)

  • 字典推导式用于从键值对构建字典。

3.1、基本语法:

{key_expression: value_expression for item in iterable if condition}

3.2、示例:

# 普通方式
squared_dict = {}
for i in range(10):
squared_dict[i] = i * i
# 字典推导式
squared_dict = {i: i * i for i in range(10)}
print(squared_dict) # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

4、生成器表达式(Generator Expressions)

  • 生成器表达式与列表推导式类似,但它生成的是一个生成器对象,该对象在迭代时才生成值,这使得它们在处理大数据集时更加内存高效。

4.1、基本语法:

(expression for item in iterable if condition)

4.2、示例:

# 列表推导式
numbers = [i for i in range(1000000)]
# 生成器表达式
numbers_gen = (i for i in range(1000000))

5、推导式中的循环和条件

  • 推导式可以包含多个 forif 子句,以支持更复杂的逻辑。
# 过滤偶数并计算平方
even_squares = [i * i for i in range(10) if i % 2 == 0]
print(even_squares) # 输出: [0, 4, 16, 36, 64]
# 多层循环
matrix = [[j for j in range(5)] for i in range(3)]
print (matrix) # 输出: [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]

6、推导式与普通循环的性能对比

  • 推导式通常比等价的普通循环代码执行得更快,因为 Python 在内部对推导式进行了优化。然而,对于非常简单的迭代,两者的性能差异可能不明显。

7、注意事项

  • 推导式应该用于使代码更清晰、更简洁的情况。如果推导式过于复杂,可能会降低代码的可读性,这时应考虑使用普通的循环结构。
  • 推导式中的变量作用域:在推导式中定义的变量(如循环变量)在推导式外部是不可见的。

拓展:使用列表推导式创建元组

  • 列表推导式可以生成列表,然后我们可以使用 tuple() 函数将这个列表转换为元组。这种方式在需要从推导式生成的数据创建元组时非常有用。
# 使用列表推导式生成列表,然后转换为元组
my_tuple = tuple([x * 2 for x in range(5)])
print(my_tuple) # 输出: (0, 2, 4, 6, 8)