为什么 *Args和** Kwargs似乎在班级装饰者中消失了



使用装饰师练习,发现这种行为很奇怪:

def test_decorator(cls, *args, **kwargs):
    print (args, kwargs)
    def build(*args, **kwargs):
        print (args, kwargs)
        return cls(*args, **kwargs)
    return build
@test_decorator
class Test:
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
t = Test(1, 2, 3, val = 4)
print (t.args, t.kwargs)
# output
# () { }
# (1, 2, 3) {'val' = 4}
# (1, 2, 3) {'val' = 4}

为什么装饰器中的第一个print显示空容器?此外,如果我将build()定义为:

def build():
    return cls(*args, **kwargs)

我知道由于嵌套函数范围而失败。我只是不确定为什么它们在致电build之前不存在并突然返回范围。

您在这里有两个不同的可可:

  • test_decorator()
  • test_decorator()build()
  • 返回的包装器

您正在混淆这两个。

第一个被称为仅类别,因为

@test_decorator
class Test:
    # ...

真的只是

class Test:
    # ...
Test = test_decorator(Test)

该调用仅传递一个参数,将被装饰的类,分配给cls名称。 argskwargs对该呼叫的参数保持为空。

随后调用Test(...)时,您确实在调用build(...)。该调用传递由本地argskwargs对象捕获的参数,并传递给cls(...)(引用原始类对象(。这些参数并没有丢失,它们显然已传递到__init__方法,并且使用相同名称的实例属性已正确设置。

要区分不同的接收参数,请从给它们不同的名称开始,然后增强您的print()输出:

def test_decorator(cls, *decorator_args, **decorator_kwargs):
    print('Decorator called with ({!r}, *{!r}, **{!r})'.format(
        cls, decorator_args, decorator_kwargs))
    def build(*build_args, **build_kwargs):
        print('build() wrapper called with (*{!r}, **{!r})'.format(
            build_args, build_kwargs))
        print('The decorator was originally called with ({!r}, *{!r}, **{!r})'.format(
            cls, decorator_args, decorator_kwargs))
        return cls(*build_args, **build_kwargs)
    return build

现在输出变为:

>>> @test_decorator
... class Test:
...     def __init__(self, *args, **kwargs):
...         self.args = args
...         self.kwargs = kwargs
...
Decorator called with (<class '__main__.Test'>, *(), **{})
>>> t = Test(1, 2, 3, val = 4)
build() wrapper called with (*(1, 2, 3), **{'val': 4})
The decorator was originally called with (<class '__main__.Test'>, *(), **{})
>>> t.args, t.kwargs
((1, 2, 3), {'val': 4})

请注意,执行class语句时,装饰器用... 输出产生,而t = Test(...)调用触发了 build((包装器,称为... 输出。

最新更新