在python中覆盖@classmethods的__str__方法

shr*_*are 4 python oop methods class class-method

我试图覆盖__str____repr__类,如下面的代码所示。每当我调用 instance_method 时都会调用新方法,但对 class_method 的对象调用保持不变(请参阅下面的代码片段和输出,以便于了解)。有没有办法可以覆盖__str__and __repr__for@classmethod以便cls可以更改的值?

我也尝试添加__str____repr__as@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))

Run Code Online (Sandbox Code Playgroud)

上面代码的输出:

class method '<class '__main__.Abc'>'
static method
instance method class method
static method
class method '<class '__main__.Abc'>'
6
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 9

Python 不会__str__在类本身上查找 a ,就像它不会__str__在实例上使用set一样。这适用于所有特殊方法,请参阅Python 数据模型中的特殊方法查找

对于自定义类,特殊方法的隐式调用只有在对象类型上定义时才能保证正常工作,而不是在对象的实例字典中。

简而言之,str(something)不使用something.__str__(),它本质上使用type(something).__str__(something) (*)正是因为您不希望__str__类上的定义在您使用时中断str(class_object),其中class_object.__str__()没有实例传入 as 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"
Run Code Online (Sandbox Code Playgroud)

metaclass=MetaAbc语法告诉Python来使用MetaAbc,而不是仅仅type作为的元类Abc类; 现在type(Abc)返回MetaAbc

>>> type(Abc)
<class '__main__.MetaAbc'>
Run Code Online (Sandbox Code Playgroud)

and 和MetaAbc.__repr__andMetaAbc.__str__用于表示类,或将其转换为字符串;处理实例时使用类上的方法:

>>> Abc
__repr__ on the metaclass
>>> print(Abc)
__str__ on the metaclass
>>> Abc('foo')
instance method repr
>>> print(Abc('foo'))
Added foo
Run Code Online (Sandbox Code Playgroud)

@classmethod装饰并没有把一个方法到不同的命名空间; 类方法是一个类的普通属性,只是被不同地绑定。@classmethod例如,仍然可以在实例上访问,但将始终传递给类对象,即使通过实例访问时也是如此:

>>> Abc.class_method()
class method '__str__ on the metaclass'
>>> Abc("foo").class_method()
class method '__str__ on the metaclass'
Run Code Online (Sandbox Code Playgroud)

(*) Python 使用描述符绑定来实现方法、类方法和静态方法。特殊方法查找通过遍历类层次结构直接查找函数对象,以避免触发正常绑定过程,然后手动绑定它们。所以str(something)翻译成next(c.__dict__['__str__'] for c in type(something).__mro__ if '__str__' in c.__dict__).__get__(something, type(something))(). 这有点啰嗦,对于普通方法,这可以简化type(something).__str__(something)为具有相同效果。