无法将__repr __ / __ str__动态绑定到使用type创建的类

时间:2014-02-19 16:54:49

标签: python types

我正在为python编写自己的Enum类,但我无法让__str____repr__正常工作,我做错了什么?

In [2]: x = Enum(X=1, Y=2)

In [3]: x
Out[3]: common.utils.Enum

In [4]: str(x)
Out[4]: "<class 'common.utils.Enum'>"

In [5]: x.__repr__
Out[5]: <bound method type.reprfun of <class 'common.utils.Enum'>>

In [6]: x.__repr__()
Out[6]: 'Enum(Y=2, X=1)' 

代码本身:

def Enum(*args, **kwargs):
    enums = dict(zip(args, range(len(args))), **kwargs)
    def reprfun(self):
        res = 'Enum(' +\
            ', '.join(map(lambda x: '{}={}'.format(x[0],x[1]), enums.items())) +\
            ')'
        return res

    reverse = dict((value, name) for name, value in enums.items())
    typedict = enums.copy()
    typedict['name'] = reverse
    instance = type('Enum', (), typedict)
    instance.__repr__ = types.MethodType(reprfun, instance)
    instance.__str__ = types.MethodType(reprfun, instance)
    return instance

1 个答案:

答案 0 :(得分:7)

必须在类中添加特殊方法,而不是实例。总是在类型上查找任何特殊方法。

如果Python不能像那样工作,你就不能使用repr(ClassObj),因为它会调用ClassObj.__repr__方法,它会将self作为第一个参数。所以Python改为调用type(obj).__repr__(obj)

来自datamodel documentation

  

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

     

[...]

     

此行为背后的基本原理在于许多特殊方法,例如哈希()和 repr (),这些方法由所有对象(包括类型对象)实现。如果这些方法的隐式查找使用了传统的查找过程,那么在类型对象本身上调用它们时会失败:

>>>
>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument

以下作品:

typedict = enums.copy()
typedict.update({
    'name': reverse,
    '__repr__': reprfun,
    '__str__': reprfun,
})

instance = type('Enum', (), typedict)
return instance

你确实要小心命名; instance绑定到类对象,而不是实例。这个名字因此具有误导性。您可能希望使用clsclassobj或类似代替instance

演示:

>>> x = Enum(X=1, Y=2)
>>> x
<class '__main__.Enum'>
>>> x.__repr__
<unbound method Enum.reprfun>
>>> x()
Enum(Y=2, X=1)
>>> str(x())
'Enum(Y=2, X=1)'
>>> repr(x())
'Enum(Y=2, X=1)'