On Sat, Oct 05, 2013 at 05:33:46AM -0700, Albert-Jan Roskam wrote: > Hi, > > On http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ I saw > a very cool and useful example of a class decorator. It (re)implements > __str__ and __unicode__ in case Python 2 is used. For Python 3, the > decorator does nothing. I wanted to generalize this decorator so the > __str__ method under Python 2 encodes the string to an arbitrary > encoding. This is what I've created: http://pastebin.com/vghD1bVJ. > > It works, but the code is not very easy to understand, I am affraid.
It's easy to understand, it's just doing it the wrong way. It creates and subclass of your class, which it shouldn't do. Here's a better approach: inject the appropriate methods into the class directly. Here's a version for Python 3: def decorate(cls): if '__str__' not in cls.__dict__: # inject __str__ method def __str__(self): ... cls.__str__ = __str__ if '__bytes__' not in cls.__dict__: # like above return cls This avoids overwriting __str__ if it is already defined, and likewise for __bytes__. > Or is it? And I have no idea how to call the class Klass. Maybe > reimplements_Test? Is this a good approach, or can this be done in an > easier way? I would *really* like keep statements "if > sys.version_info[0] == 3..." separate from the "main" code. Also, > learning about class decorators is cool ;-). So the code below... > mehhh no sir, I don't like it. > > > def __str__(self): > > if sys.version_info[0] == 3: > blah > else: > bleh > > if sys.version_info[0] == 2: > def __unicode__(self): > blooooh That performs the version check every time the __str__ method is called. Better would be something like this: if sys.version_info[0] == 2: def __str__(self): ... def __unicode__(self): ... else: def __bytes__(self): ... def __str__(self): ... If you don't like repeating the code twice, once for version 2 and once for version 3, you may be able to define the methods once, then rename them, something like this: # Assume version 3 def __str__(self): ... def __bytes__(self): ... if sys.version_info[0] == 2: __str__.__name__ = '__unicode__' __bytes.__name__ = '__str__' # Inject into the class, as above. cls.__unicode__ = __str__ cls.__str__ = __bytes__ else: cls.__str__ = __str__ cls.__bytes__ = __bytes__ Combining this with the decorator is left for you :-) -- Steven _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor