装饰器的行为异常,如果if = 1 == 2,则执行“ if”语句:

时间:2019-01-02 16:37:47

标签: python python-3.x generator decorator python-decorators

А几个小时前,我提交了related question,并得到了答案,为什么我需要向装饰器中添加yield才能正常工作。 我最近回想起我由于某种原因而忽略了它-一种我无法解释的奇怪行为。

如果我是盲人,我会提前道歉,但是我花了几个小时盯着这个代码玩,这就是我得到的:

def decor(func):
    def wrapper(*args, **kwargs):
        if 1==2:
            print ("Generator")
            for item in func(*args, **kwargs):
                print(item)
                #yield(item)
        else:
            print ("Not generator")
            res = func(*args, **kwargs)
            print(res)
            return res
    return wrapper

@decor            
def f():
    return "a"


f()

"""
Output:
    Not generator
    a

"""

如果我在yield之前删除评论,则根本没有输出。

那是为什么?我在if 1==2:语句中所做的任何更改怎么可能对脚本产生影响?

1 个答案:

答案 0 :(得分:4)

如果函数的主体中任何地方包含yield ,则该函数为生成器函数。是否执行yield并不重要。 1 == 2为假的事实与它无关。

考虑以下功能:

def addone(numbers):
    for number in numbers:
        yield number + 1

致电addone([])会发生什么? yield从未执行,但是addone仍返回生成器。为什么这应该有所不同:

def addone(numbers):
    if numbers:
        for number in numbers:
            yield number + 1

因此很明显,实际上是否执行yield无关紧要。唯一相关的事实是yield是否存在于函数主体中。

如何修复该功能

修复相对简单,您所要做的就是将带有yield的部分拉到一个单独的函数中:

import types

def wrapper(*args, **kwargs):
    result = func(*args, **kwargs)
    if isinstance(result, types.GeneratorType):
        print("Is a generator")
        return wrap_generator(result)
    print("Not a generator")
    return result

def wrap_generator(gen):
    for item in gen:
        print(item)
        yield item

将来如何避免

通常,这里的问题是函数是生成器(使用yield)还是普通函数(使用return)。当您在同一函数中同时使用yieldreturn时,会有些混乱!

对于Python,事实证明,如果在同一函数中同时使用yieldreturn,则该函数是一个生成器函数。这可能有些令人困惑,因此从样式上来说,我通常会避免在同一函数中同时使用returnyield