这是我第一次尝试,所以...
我正在关注:https://www.python-course.eu/python3_decorators.php
目标是当我像这样初始化Foo的实例时:
f = Foo(10, [1, 2, 3, 4, 5])
print(f)的输出应如下所示:
Instance of Foo, vars = {'x': 10, 'y': [1, 2, 3, 4, 5]}
decorator类将用作一种自动的 repr 。
我有这个:
class ClassDecorator(object):
def __init__(self, cls):
self.cls = cls
print("An instance of Foo was initialized")
def __call__(self, cls, *args, **kwargs):
print("Instance of Foo, vars = ", kwargs)
@ClassDecorator
class Foo(object):
def __init__(self, x, y):
self.x = x
self.y = y
f = Foo(10, [1, 2, 3, 4, 5])
print(f)
哪种产量:
An instance of Foo was initialized
Instance of Foo, vars = {}
None
我不希望我使用* args,但是如果没有它,我的程序将出现以下错误:
Traceback (most recent call last):
An instance of Foo was initialized
File "C:/Users/Mark/PycharmProjects/main/main.py", line 17, in <module>
f = Foo(10, [1, 2, 3, 4, 5])
TypeError: __call__() takes 2 positional arguments but 3 were given
我了解遗漏的论点问题,但是如果10为'x'而[1、2、3、4、5]为'y',那么我只是不明白为什么** kwargs不足
答案 0 :(得分:1)
我认为您在这里缺少了一些不同的基本概念。
首先,当您print
一个对象,例如print(f)
时,将以__str__
类型调用f
方法。如果没有人定义__str__
,则会调用默认的object.__str__
,它只会返回f.__repr__
。
因此,如果您想更改执行print(f)
时发生的情况,则必须给f
的类型输入__str__
(或{ {1}})方法可以满足您的需求。您在其他任何地方所做的任何事情都不会产生任何效果。
初始化__repr__
的实例时,不会调用装饰器的__init__
;当 class 初始化时,它将被调用。 (或者,当装饰器在类创建后立即在类上被调用)是Foo
发生在您使用它创建实例时。
此外,__call__
不会从任何地方获取额外的__call__
参数,它只会像其他任何普通方法一样获取cls
。这就是为什么我们必须首先将修饰的类存储为self
的原因。
装饰器的要点是返回一个可以像装饰对象一样使用的对象。您的self.cls
可以像类一样被调用-但是这样做时它什么也不返回,而不是返回实例。这意味着不可能创建实例。如果尝试,您只会得到ClassDecorator
。这就是None
打印print(f)
的原因。
最后,转发参数通常同时需要None
和*args
。 **kwargs
将所有意外的位置参数收集到一个元组中,*args
将所有意外的关键字参数收集到一个dict中。有人致电**kwargs
时,有两个位置参数,没有关键字参数。因此,Foo(10, [1, 2, 3, 4, 5])
将为args
,而(10, [1, 2, 3, 4, 5])
将为kwargs
。如果您没有{}
,那么您会得到*args
,因为您没有任何显式的position-or-keyword参数来匹配这些位置参数。
因此,这是一个解决所有问题的示例。我将通过修饰修饰的类来完成此操作,但是请记住,这不是唯一的方法,并且每种方法都有其优缺点。
首先,我将展示如何编写一个装饰器,该装饰器仅对实例变量为TypeError
和x
的类执行您想要的操作。
y
现在,当您使用它时,它可以满足您的要求:
class ClassDecorator(object):
def __init__(self, cls):
def _str(self):
typ = type(self).__name__
vars = {'x': self.x, 'y': self.y}
return(f"Instance of {typ}, vars = {vars}")
cls.__str__ = _str
self.cls = cls
print(f"The class {cls.__name__} was created")
def __call__(self, *args, **kwargs):
print(f"An instance of {self.cls.__name__} was created with args {args} and kwargs {kwargs}")
return self.cls(*args, **kwargs)
当然,如果您想覆盖最后一件事,则希望使用与>>> @ClassDecorator
... class Foo(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
The class Foo was created
>>> f = Foo(10, [1, 2, 3, 4, 5])
An instance of Foo was created with args (10, 20) and kwargs {}
>>> print(f)
Instance of Foo, vars = {'x': 10, 'y': 20}
>>> f
<__main__.Foo at 0x127ecdcf8>
相同的方式定义__repr__
。
那么,如果我们想在 any 类上使用它而又不事先知道其属性是什么呢?我们可以使用__str__
模块来找到属性:
inspect