python - 在python中覆盖@classmethods的__str__方法

标签 python class oop methods class-method

我试图为类覆盖 __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/

相关文章:

python - 带有默认数据类的 SQLAlchemy 不填充 postgres 数据库

C++ 友元/多态类错误

java - 如何为每个对象使用变量

c++ - 编译器错误 : No appropriate default constructor avaible

php - 如何在 PHP 中获取对根对象的迭代对象引用?

python - 如何在opencv-python中将输出帧全部组合在一起?

python - 列表字典 : writing lists (with tab separated items) to different files for each key (Python)

python - gcloud.exceptions.Forbidden : 403 Missing or insufficient permissions

c++ - 自制 vector 类的重载 = 运算符

c++ - 关于单例