我认为你遗漏了一些不同的基本概念。
首先,当你
print
一个物体,比如
print(f)
,这就是所谓的
__str__
方法的类型
f
. 如果没有人定义
_战略__
,默认值
object.__str__
被调用,它只是返回
f.__repr__
.
所以,如果你想改变当你做一个
打印(F)
你
不得不
给
f
的A型
_战略__
(或)
__repr__
)实现您所需功能的方法。你在别的地方做的任何事都不会有任何效果。
你的装修工
__init__
当的实例
Foo
初始化;当
班
初始化。(或者,更确切地说,当修饰符在类上被调用时,就在类创建之后)它是
__call__
当您使用它来创建实例时就会发生这种情况。
还有,那
_呼叫__
不会有额外的
cls
从任何地方得到的参数
self
像其他普通方法一样。这就是为什么我们要把装饰课作为
self.cls
首先。
装饰器的作用是返回一个可以像装饰对象一样使用的对象。你的
ClassDecorator
可以像类一样调用,但这样做时它不会返回任何内容,而不会返回实例。这意味着不可能创建实例;如果您尝试,您只需
None
. 这就是为什么
打印(F)
印刷品
没有
.
最后,转发参数通常需要
*args
和
**kwargs
.
*精氨酸
将任何意外的位置参数收集到元组中,并且
**夸格斯
将任何意外的关键字参数收集到dict中。当有人调用
Foo(10, [1, 2, 3, 4, 5])
,有两个位置参数,没有关键字参数。所以
args
将
(10, [1, 2, 3, 4, 5])
和
kwargs
将
{}
. 如果你没有
*精氨酸
然后你会得到一个
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>
当然,如果你想重写最后一件事,你要定义
_报告__
和
_战略__
.
那么,如果我们想用这个
任何
类,而不预先知道它的属性是什么?我们可以使用
inspect
查找属性的模块:
def _str(self):
typ = type(self).__name__
vars = {name: value for name, value in inspect.getmembers(self) if not name.startswith('_')}
return(f"Instance of {typ}, vars = {vars}")