生成器中return与return None的PEP 8规范适配疑问
首先得给你澄清一个关键误解:PEP 8里那条「函数声明需保持一致的返回模式」的规则,并不适用于生成器函数,或者说,生成器的「返回逻辑」和普通函数根本不是一回事儿。
咱们一步步拆解你的问题:
1. PEP 8的返回规则针对的是普通函数
PEP 8里要求的「要么全部返回表达式,要么全部不返回」,是给那些没有yield、靠return传递结果的普通函数定的规矩。比如一个普通函数,不能有的分支return 1,有的分支啥也不return(隐式返回None),这会让调用者困惑。但生成器不一样——当你调用一个生成器函数时,它一开始就返回了一个生成器对象,而不是你写的return语句里的内容,这和普通函数的返回逻辑完全不同。
2. 生成器里return的实际作用(以及你怎么拿到那个100)
你代码里的return 100不是没用,只是你没找对获取它的方式。生成器里的return语句(不管带不带值),核心作用是提前终止迭代;如果带了值,这个值会被放到StopIteration异常的value属性里。比如你可以这样拿到那个100:
def hello(): for i in range(5): yield i return 100 g = hello() try: while True: next(g) except StopIteration as e: print(e.value) # 这里会输出100
不过这个特性是Python 3.3之后才支持的,之前的版本里生成器用return会直接报错。但日常开发中很少有人这么用,因为大多数时候我们只是遍历生成器产出的yield值,不会特意去捕获StopIteration的value。
3. 为什么生成器末尾加return None毫无意义
当生成器执行完所有yield语句后,会自动抛出StopIteration异常,相当于隐式终止了迭代。这时候加个return None完全是冗余操作——既不会改变生成器的行为,也不会给调用者带来任何有用信息,PEP 8也明确不推荐这种多余的写法。
回到你的代码例子:用列表推导[x for x in hello()]或者直接遍历生成器时,Python会自动捕获StopIteration异常并终止循环,不会把异常的value暴露出来,所以你看不到那个100。这不是return没用,只是这种遍历方式故意屏蔽了终止信息而已。
总结一下:
- 生成器不需要遵循普通函数的「一致返回模式」,PEP 8没有强制要求你加return语句
- 生成器里的return是用来提前终止迭代的,返回值藏在StopIteration的value里,但实际场景中很少用到
- 别在生成器末尾加
return None,纯粹是画蛇添足
内容的提问来源于stack exchange,提问作者Bram Vanroy

