关键字

yield

yield 是 Python 中的一个关键字,用于定义生成器函数(generator function)。生成器函数是一种特殊的函数,它可以逐步产生值,而不是一次性返回所有结果。yield 的作用是将函数变成一个生成器,每次调用生成器的 __next__() 方法时,函数会执行到 yield 语句并返回一个值,然后暂停执行,直到下一次调用。


yield 的基本用法

示例 1:简单的生成器函数

1
2
3
4
5
6
7
8
9
10
def simple_generator():
yield 1
yield 2
yield 3

# 使用生成器
gen = simple_generator()
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
print(next(gen)) # 输出: 3
  • 每次调用 next(gen),函数会从上次暂停的地方继续执行,直到遇到下一个 yield
  • 当没有更多的值可以生成时,会抛出 StopIteration 异常。

示例 2:使用 for 循环遍历生成器

1
2
3
4
5
6
7
8
def simple_generator():
yield 1
yield 2
yield 3

# 使用 for 循环遍历生成器
for value in simple_generator():
print(value)

输出:

1
2
3
1
2
3
  • for 循环会自动处理 StopIteration 异常,因此不需要手动调用 next()

yield 的优势

  1. 惰性求值

    • 生成器不会一次性生成所有值,而是按需生成,节省内存。
    • 适合处理大量数据或无限序列。
  2. 代码简洁

    • 使用 yield 可以避免手动实现迭代器协议(__iter____next__)。
  3. 状态保持

    • 生成器函数会记住上次执行的状态,下次调用时从上次暂停的地方继续。

yield 的高级用法

示例 3:生成无限序列

1
2
3
4
5
6
7
8
9
10
11
12
def infinite_sequence():
num = 0
while True:
yield num
num += 1

# 使用生成器
gen = infinite_sequence()
print(next(gen)) # 输出: 0
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
# 可以无限调用 next(gen)
  • 这个生成器会无限生成递增的整数。

示例 4:使用 yield 实现斐波那契数列

1
2
3
4
5
6
7
8
9
10
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b

# 使用生成器
gen = fibonacci()
for _ in range(10):
print(next(gen))

输出:

1
2
3
4
5
6
7
8
9
10
0
1
1
2
3
5
8
13
21
34
  • 这个生成器会无限生成斐波那契数列的值。

示例 5:yield from(委托生成器)

yield from 用于将生成器的控制权委托给另一个生成器。

1
2
3
4
5
6
7
8
9
10
11
12
def sub_generator():
yield 1
yield 2

def main_generator():
yield 'Start'
yield from sub_generator()
yield 'End'

# 使用生成器
for value in main_generator():
print(value)

输出:

1
2
3
4
Start
1
2
End
  • yield from 可以简化生成器的嵌套调用。

yield 与 return 的区别

特性 yield return
返回值 每次生成一个值,函数暂停 返回一个值,函数结束
状态保持 函数状态会被保存 函数状态不会被保存
适用场景 生成器函数 普通函数
内存占用 惰性求值,节省内存 一次性返回所有结果,占用内存

总结

  • yield 是 Python 中实现生成器的关键,适合处理大量数据或需要惰性求值的场景。
  • 生成器函数通过 yield 逐步返回值,并保持函数状态,直到生成所有值。
  • yield from 可以简化生成器的嵌套调用。

assert

assert 是 Python 中的一个关键字,用于调试和测试代码。它的作用是检查某个条件是否为真,如果条件为假,则会触发 AssertionError 异常。assert 通常用于确保程序在某个关键点的状态符合预期,如果不符合,则立即停止程序并抛出错误。


assert 的基本语法

1
assert condition, message
  • condition:需要检查的条件表达式。如果为 True,程序继续执行;如果为 False,则抛出 AssertionError
  • message(可选):当条件为 False 时,抛出的异常信息。如果未提供,则使用默认的 AssertionError

assert 的作用

  1. 调试工具

    • 用于在开发阶段检查代码逻辑是否正确。
    • 如果条件不满足,程序会立即停止,方便定位问题。
  2. 测试工具

    • 在单元测试中,用于验证函数的输出是否符合预期。
  3. 文档工具

    • 通过 assert 可以清晰地表达代码的预期行为。

assert 的示例

示例 1:简单的 assert 用法

1
2
x = 10
assert x == 10, "x 应该等于 10"
  • 如果 x == 10True,程序继续执行。
  • 如果 x == 10False,则抛出 AssertionError,并显示消息 "x 应该等于 10"

示例 2:检查函数返回值

1
2
3
4
5
6
def divide(a, b):
assert b != 0, "除数不能为 0"
return a / b

print(divide(10, 2)) # 输出: 5.0
print(divide(10, 0)) # 触发 AssertionError: 除数不能为 0
  • 在函数中使用 assert 可以确保输入参数的有效性。

示例 3:检查列表是否非空

1
2
3
4
5
6
7
def process_list(items):
assert len(items) > 0, "列表不能为空"
for item in items:
print(item)

process_list([1, 2, 3]) # 正常执行
process_list([]) # 触发 AssertionError: 列表不能为空

assert 的注意事项

  1. 不要用于数据验证

    • assert 主要用于调试和测试,不应该用于检查用户输入或外部数据。
    • 因为 Python 可以通过 -O(优化模式)运行,此时所有的 assert 语句会被忽略。
  2. 避免副作用

    • assert 的条件表达式不应该包含有副作用的操作(如修改全局变量、调用函数等),因为在优化模式下这些操作会被跳过。
  3. 替代方案

    • 对于数据验证或输入检查,应该使用 if 语句并手动抛出异常(如 ValueErrorTypeError 等)。

assert 与 if 的区别

特性 assert if
用途 调试和测试 通用条件判断
触发异常 触发 AssertionError 需要手动抛出异常
优化模式 -O 模式下会被忽略 不受影响
适用场景 检查内部逻辑是否正确 检查用户输入或外部数据

assert 的优化模式

Python 支持以优化模式运行脚本,此时所有的 assert 语句会被忽略。可以通过以下命令启用优化模式:

1
python -O script.py
  • 在优化模式下,assert 语句不会被执行,因此不能依赖它来实现关键逻辑。

总结

  • assert 是一个强大的调试工具,用于检查代码逻辑是否符合预期。
  • 它适合在开发和测试阶段使用,但不适合用于生产环境中的数据验证。
  • 如果需要更健壮的输入检查,应该使用 if 语句并手动抛出异常。