Skip to content Skip to sidebar Skip to footer

Can't Dynamically Bind __repr__/__str__ To A Class Created With Type

I'm rolling my own Enum class for python and I'm having trouble getting __str__ and __repr__ to work correctly, what am I doing wrong? In [2]: x = Enum(X=1, Y=2) In [3]: x Out[3]:

Solution 1:

Special methods must be added to the class, not to the instance. Any special method is always looked up on the type.

If Python didn't work like that, you couldn't use repr(ClassObj) as that'd call the ClassObj.__repr__ method which would expect self as a first argument. So Python calls type(obj).__repr__(obj) instead.

From the datamodel documentation:

For new-style 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.

[...]

The rationale behind this behaviour lies with a number of special methods such as hash() and repr() that are implemented by all objects, including type objects. If the implicit lookup of these methods used the conventional lookup process, they would fail when invoked on the type object itself:

>>>
>>> 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

The following works:

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

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

You do want to be careful with the naming though; instance is bound to a class object here, not an instance. The name is thus misleading. You may want to use cls or classobj or similar instead of instance.

Demo:

>>>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)'

Post a Comment for "Can't Dynamically Bind __repr__/__str__ To A Class Created With Type"