【问题标题】:Decorated generator function装饰生成器功能
【发布时间】:2022-01-09 01:30:03
【问题描述】:

我有一个装饰器:

def remediation_decorator(dec_mthd):
    def new_func(*args, **kwargs):
        try:
            return dec_mthd(*args, **kwargs)
        except (KeyError, HTTPError) as err:
            print(f'error = {err}... call the remediation function')
    return new_func

在生成器函数内部,调用另一个函数在特定条件下引发特定异常:

def check(number):
    if number == 1:
        raise HTTPError
    if number == 2:
        raise KeyError

这个生成器函数是这样装饰的:

@remediation_decorator
def dec_mthd_b(number):
    check(number)
    for i in range(0,3):
        yield i+1

当 check 函数引发异常时,装饰器的 except 不会被命中。

[ins] In [16]: dec_mthd_b(1)
Out[16]: <generator object dec_mthd_b at 0x10e79cc80>

它的行为似乎是这样的,因为它是一个生成器函数 - 来自Yield expressions

当调用生成器函数时,它会返回一个称为生成器的迭代器。

(我想知道是否从字面意义上理解“它首先返回迭代器而不管函数中的其他逻辑”,因此为什么 check() 不会引发异常?)

和,

暂停是指保留所有局部状态,包括局部变量的当前绑定、指令指针、内部评估堆栈,以及任何异常处理的状态

我是否理解正确?请问谁能进一步解释一下?

【问题讨论】:

  • 很遗憾,我不知道答案,但我为自己添加了 this question 的书签,因为我总是忘记 yield 和生成器是如何工作的。也许它会有一些用处。
  • 有一个很好的概述here。再读一遍,我认为它很好地解释了这里发生的事情,因为它说“当你调用函数时,你在函数体中编写的代码不会运行”
  • next(dec_mthd_b(1)) 引发所需的异常

标签: python generator decorator


【解决方案1】:

你已经正确理解了。下面的代码会抛出异常。创建生成器时,不会执行任何操作。您需要获取下一个元素,因此从生成器中获取值,然后它将引发异常。

g = dec_mthd_b(1)
next(g) #throws httperror

其实迭代就是这样完成的,我们反复调用next方法,直到抛出IterationError异常。

【讨论】:

    【解决方案2】:

    是的,你明白了。 @remediation_decorator 是 Python 中用于装饰器的语法糖。我将使用详细(?)形式:

    def dec_mthd_b(number):
        check(number)
        for i in range(0, 3):
            yield i + 1
    
    dec_mthd_b = remediation_decorator(dec_mthd_b)
    

    这条线是做什么的? remediation_decorator 是您的装饰器,它为您提供内部功能,在您的情况下为 new_func

    new_func 是什么?它是一个普通函数,当你调用它时,它会运行函数体。

    new_func 会返回什么? dec_mthd(*args, **kwargs).

    这里dec_mthd 指向dec_mthd_b,它又是一个函数。但是当你调用它时,由于里面有dec_mthd_b has yield`关键字,它返回你生成器对象。

    现在重点来了。你的内部函数体,这里是new_func,执行没有任何问题。你得到了你的生成器对象。没有引发错误...

    # this is the result of calling inner function, which gives you the generator object
    gen = dec_mthd_b(1)
    
    # Here is where you're going to face the exceptions.
    for i in gen:
        print(i)
    

    for 循环会发生什么? Python 运行dec_mthd_b 的主体。错误是从那里引发的......

    因此,为了捕获异常,您有两种选择,要么在 dec_mthd_b 中捕获它,要么在最后一个 for 循环中。

    【讨论】:

      猜你喜欢
      • 2021-04-06
      • 2021-12-05
      • 2023-03-28
      • 2021-12-15
      • 2021-01-17
      • 2017-05-13
      • 2015-05-25
      • 2013-07-30
      • 1970-01-01
      相关资源
      最近更新 更多