Question

I have some code I developed in python 2.4++ and you bet, I have to backport it to python 2.1!

function decorators were so attractive that I have used @classmethod at a few spots, without taking notice of the fact that it is only available starting at version 2.4. the same functionality is offered by function modifiers but these appeared in python 2.2. cfr: http://www.python.org/dev/peps/pep-0318/

now some of our customers appear to be still dependent on python 2.1 (ArcGIS 9.1 ships with it and makes it not upgradable), where not even the function modifiers are available...

I have been looking for some function modifier definitions in python 2.1, but I did not find any (I mean: working). anybody successfully solved this problem?

to be more concrete, I need a way to run this 2.4 code in python 2.1:

Python 2.4.6 (#2, Mar 19 2009, 10:00:53) 
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class sic:
...   def f(cls):
...     print cls.__name__
...   f = classmethod(f)
... 
>>> sic().f()
sic
>>> sic.f()
sic
>>> 
Was it helpful?

Solution

Just like in my old recipe for 2.1 staticmethod:

class staticmethod:
    def __init__(self, thefunc): self.f = thefunc
    def __call__(self, *a, **k): return self.f(*a, **k)

you should be able to do a 2.1 classmethod as:

class classmethod:
    def __init__(self, thefunc): self.f = thefunc
    def __call__(self, obj, *a, **k): return self.f(obj.__class__, *a, **k)

No @-syntax of course, but rather the old way (like in 2.2):

class sic:
  def f(cls): ...
  f = classmethod(f)

If this doesn't work (sorry, been many many years since I had a Python 2.1 around to test), the class will need to be supplied more explicitly -- and since you call classmethod before the class object exists, it will need to be by name -- assuming a global class,

class classmethod2:
    def __init__(self, thefunc, clsnam):
        self.f = thefunc
        self.clsnam = clsnam
    def __call__(self, *a, **k):
        klass = globals()[self.clsnam]
        return self.f(klass, *a, **k)

class sic2:
  def f(cls): ...
  f = classmethod2(f, 'sic2')

It's really hard to find elegant ways to get the class object (suppressing the need for self is the easy part, and what suffices for staticmethod: you just need to wrap the function into a non-function callable) since 2.1 had only legacy (old-style classes), no usable metaclasses, and thus no really good way to have sic2.f() magically get that cls.

Since the lack of @ syntax in 2.1 inevitably requires editing of code that uses @classmethod, an alternative is to move the functionality (decorating some methods to be "class" ones) to right AFTER the end of the class statement (the advantage is that the class object does exist at that time).

class classmethod3:
    def __init__(self, thefunc, klass):
        self.f = thefunc
        self.klass = klass
    def __call__(self, *a, **k):
        return self.f(self.klass, *a, **k)

def decorate(klass, klassmethodnames):
  for n in klassmethodnames:
    thefunc = klass.__dict__[n]
    setattr(klass, n, classmethod3(thefunc, klass))

class sic2:
  def f(cls): ...
  def g(self): ...
  def h(cls): ...
decorate(sic2, ['f', 'h'])

OTHER TIPS

If just the @classmethod need to be backported to Python 2.1.
There is a recipe of Classmethod emulation in python2.1
Hope this help.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top