While there are compatibility libraries; six and future being the 2 most widely known, sometimes one needs to live without compatibility libs. You can always write your own class decorator, and put it into say mypackage/compat.py. The following works nicely for writing the class in Python 3 format and converting the 3-ready class to Python 2 if needed (the same can be used for next vs __next__, etc:
import sys
if sys.version_info[0] < 3:
def py2_compat(cls):
if hasattr(cls, '__str__'):
cls.__unicode__ = cls.__str__
del cls.__str__
# or optionally supply an str that
# encodes the output of cls.__unicode__
return cls
else:
def py2_compat(cls):
return cls
@py2_compat
class MyPython3Class(object):
def __str__(self):
return u'Here I am!'
(notice that we are using u'' prefix which is PyPy 3, and Python 3.3+ compatible only, so if you need to be compatible with Python 3.2, then you need to adjust accordingly)
To supply a __str__ method that encodes the __unicode__ to UTF-8 in Python 2, you can replace the del cls.__str__ with
def __str__(self):
return unicode(self).encode('UTF-8')
cls.__str__ = __str__
__str__changes between Python 2 and 3. In Python 2, it must return bytes, in Python 3, it must return Unicode.__unicode__and/or__str__could do this simple conversion. That's essentially what the answers do.__str__exists in both Python 2 and Python 3, and its return value must be defined differently. Essentially that'd be changing the conditionals that my code executes once per initialization time into once per each invocation, hardly handy anymore.