我试图为类覆盖 __str__
和 __repr__
,如下面的代码所示。每当我调用 instance_method 时都会调用新方法,但对 class_method 的对象调用保持不变(为清楚起见,请参阅下面的代码片段和输出)。有没有一种方法可以覆盖 @classmethod
的 __str__
和 __repr__
以便可以更改 cls
的值?
我也尝试过将 __str__
和 __repr__
添加为 @classmethod
但没有任何改变。
class Abc:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Added {self.name}"
def __repr__(self):
return f"instance method repr"
def instance_method(self):
print(f"instance method {self}")
@classmethod
def __repr__(cls):
return f"class method"
@classmethod
def __str__(cls):
return f"class method"
@classmethod
def class_method(cls):
print(f"class method '{cls}'")
@staticmethod
def static_method():
print(f"static method")
def add(self, a: int,b: int,c: int) -> int:
return a+b+c
o = Abc("alpha")
o.class_method()
o.static_method()
o.instance_method()
Abc.static_method()
Abc.class_method()
print(o.add(1,2,3))
以上代码的输出:
class method '<class '__main__.Abc'>'
static method
instance method class method
static method
class method '<class '__main__.Abc'>'
6
最佳答案
Python 不会在类本身上寻找 __str__
,就像它不会在实例上使用 __str__
集一样。这适用于所有 特殊方法,参见Special method lookup在 Python 数据模型中:
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.
简而言之,str(something)
没有使用something.__str__()
,它本质上使用了type(something).__str__(something)
(*) 正是因为当您使用 str(class_object)
时,您不希望类上 __str__
的定义中断,其中 class_object.__str__()
没有要作为 self
传入的实例。
你必须定义一个 metaclass ,因为这是生成类并由 type(class_object)
返回的“东西”:
class MetaAbc(type):
def __repr__(cls):
return "__repr__ on the metaclass"
def __str__(cls):
return "__str__ on the metaclass"
class Abc(metaclass=MetaAbc):
def __init__(self, name):
self.name = name
def __str__(self):
return f"Added {self.name}"
def __repr__(self):
return "instance method repr"
metaclass=MetaAbc
语法告诉 Python 使用 MetaAbc
而不仅仅是 type
作为 Abc
的元类类(class);现在 type(Abc)
返回 MetaAbc
:
>>> type(Abc)
<class '__main__.MetaAbc'>
和MetaAbc.__repr__
和MetaAbc.__str__
用于表示一个类,或将其转换为字符串;类上的方法在处理实例时使用:
>>> Abc
__repr__ on the metaclass
>>> print(Abc)
__str__ on the metaclass
>>> Abc('foo')
instance method repr
>>> print(Abc('foo'))
Added foo
@classmethod
装饰器不会将方法放入不同的命名空间;类方法是类的普通属性,只是简单地以不同方式绑定(bind)。例如,@classmethod
仍然可以在实例上访问,但是将总是传递给类对象,即使是通过实例访问也是如此:
>>> Abc.class_method()
class method '__str__ on the metaclass'
>>> Abc("foo").class_method()
class method '__str__ on the metaclass'
(*) Python 使用 descriptor binding实现方法、类方法和静态方法。特殊方法查找通过遍历类层次结构直接查找函数对象以避免触发正常的绑定(bind)过程,然后手动绑定(bind)它们。所以 str(something)
转换为 next(c.__dict__['__str__'] for c in type(something).__mro__ if '__str__' in c.__dict__).__get__(something,输入(某物))()
。这有点啰嗦,对于 普通 方法,这可以简化为 type(something).__str__(something)
因为它具有相同的效果。
关于python - 在python中覆盖@classmethods的__str__方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57911603/