Trying to change the __unicode__ method on an instance after it’s created produces different results on Python 2.5 and 2.6.
Here’s a test script:
class Dummy(object):
def __unicode__(self):
return u'one'
def two(self):
return u'two'
d = Dummy()
print unicode(d)
d.__unicode__ = d.two
print unicode(d)
print d.__unicode__()
On Python 2.5, this produces
one
two
two
That is, changing the instance’s __unicode__ also changes unicode(instance)
On Python 2.6, this produces
one
one
two
So, after a change, unicode(instance) and instance.__unicode__() return different results.
Why? How can I get this working on Python 2.6?
(For what it’s worth, the use case here is that I want to append something to the output of __unicode__ for all subclasses of a given class, without having to modify the code of the subclasses.)
Edit to make the use case a little clearer
I have Class A, which has many subclasses. Those subclasses define simple __unicode__ methods. I want to add logic so that, for instances of a Class A subclass, unicode(instance) gets something tacked on to the end. To keep the code simple, and because there are many subclasses I don’t want to change, I’d prefer to avoid editing subclass code.
This is actually existing code that works in Python 2.5. It’s something like this:
class A(object):
def __init__(self):
self._original_unicode = self.__unicode__
self.__unicode__ = self.augmented_unicode
def augmented_unicode(self):
return self._original_unicode() + u' EXTRA'
It’s this code that no longer works on 2.6. Any suggestions on how to achieve this without modifying subclass code? (If the answer involves metaclasses, note that class A is itself a subclass of another class — django.db.models.Model — with a pretty elaborate metaclass.)
It appears that you are not allowed to monkey-patch protocol methods (those that begin and end with double underscores) :
That being the case, you may be stuck unless you can go with ~unutbu’s answer.
EDIT: Or, you can have the base class
__unicode__method search the instance object’s dict for a__unicode__attribute. If it’s present, then__unicode__is defined on the instance object, and the class method calls the instance method. Otherwise, we fall back to the class definition of__unicode__.I think that this could allow your existing subclass code to work without any changes. However, it gets ugly if the derived class wants to invoke the class implementation — you need to be careful to avoid infinite loops. I haven’t implemented such hacks in this example; merely commented about them.
Testing with Python 2.6 produces the following output: