在python中为@classmethods重写__str__方法 [英] Overriding the __str__ method for @classmethods in python

查看:220
本文介绍了在python中为@classmethods重写__str__方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I was trying to override __str__ and __repr__ for class as shown in the code below. The new methods are called whenever I call the instance_method but the object calls for class_method remains the same (Please see the code snippet and the output below for clarity). Is there a way possible to override __str__ and __repr__ for @classmethod so that the value of cls can be changed?

我还尝试将__str____repr__添加为@classmethod,但没有任何改变.

I have also tried adding __str__ and __repr__ as @classmethod but nothing changed.

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__一样.这适用于所有特殊方法,请参见 特殊方法查找 :

Python doesn't look for a __str__ on the class itself, just like it won't use __str__ set on an instance. This applies to all special methods, see Special method lookup in the Python datamodel:

对于自定义类,只有在对对象的类型(而不是在对象的实例字典中)进行定义的情况下,才能保证对特殊方法的隐式调用可以正常工作.

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__定义当您使用str(class_object)时,其中class_object.__str__()没有实例作为self传递.

In short, str(something) does not use something.__str__(), it essentially uses type(something).__str__(something) (*) exactly because you wouldn't want the definition of __str__ on a class to break when you use str(class_object), where class_object.__str__() doesn't have an instance to pass in as self.

您必须定义 元类 ,因为那是构成类并由type(class_object)返回的东西":

You'll have to define a metaclass, because that's the 'thing' that makes classes and is returned by 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类的元类;现在type(Abc)返回MetaAbc:

The metaclass=MetaAbc syntax tells Python to use MetaAbc instead of just type as metaclass of the Abc class; now type(Abc) returns MetaAbc:

>>> type(Abc)
<class '__main__.MetaAbc'>

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

and MetaAbc.__repr__ and MetaAbc.__str__ are used when representing a class, or converting it to a string; the methods on the class are used when dealing with an instance:

>>> Abc
__repr__ on the metaclass
>>> print(Abc)
__str__ on the metaclass
>>> Abc('foo')
instance method repr
>>> print(Abc('foo'))
Added foo

@classmethod装饰器不会将方法放入其他名称空间;类方法是类的常规属性,并且仅以不同的方式绑定.例如,@classmethod仍可在实例上访问,但即使通过实例访问,也将始终将 传递给类对象:

The @classmethod decorator does not put a method into a different namespace; class methods are normal attributes of a class and are simply bound differently. @classmethod's are still accessible on the instance, for example, but will always be passed the class object, even when accessed via the instance:

>>> Abc.class_method()
class method '__str__ on the metaclass'
>>> Abc("foo").class_method()
class method '__str__ on the metaclass'


(*) Python使用 描述符绑定 来实现方法,类方法和静态方法.特殊方法查找通过遍历类层次结构直接查找功能对象,以避免触发正常的绑定过程,然后手动绑定它们.因此,str(something)转换为next(c.__dict__['__str__'] for c in type(something).__mro__ if '__str__' in c.__dict__).__get__(something, type(something))().对于 normal 方法来说,这有点麻烦,因为可以起到相同的作用,因此可以简化为type(something).__str__(something).


(*) Python uses descriptor binding to implement methods, classmethods and staticmethods. Special method lookups look up the function object directly by traversing the class hierarchy to avoid triggering the normal binding process, then bind them manually. So str(something) translates to next(c.__dict__['__str__'] for c in type(something).__mro__ if '__str__' in c.__dict__).__get__(something, type(something))(). That's a bit of a mouthful, for normal methods this can be simplified to type(something).__str__(something) as that has the same effect.

这篇关于在python中为@classmethods重写__str__方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆