En Mon, 31 Dec 2007 12:08:43 -0200, Steven D'Aprano <[EMAIL PROTECTED]> escribi�:
> On Mon, 31 Dec 2007 05:47:31 -0800, iu2 wrote: > >> I'm trying to make a method call automatically to its super using this >> syntax: > > > def chain(meth): # A decorator for calling super. > def f(self, *args, **kwargs): > result = meth(self, *args, **kwargs) > S = super(self.__class__, self) > getattr(S, meth.__name__)(*args, **kwargs) > return result > f.__name__ = "chained_" + meth.__name__ > return f > > > > class A(object): > def foo(self, x): > print "I am %s" % self > return x > > class B(A): > @chain > def foo(self, x): > print "This is B!!!" > return x + 1 If you later inherit from B and try to @chain a method, nasty things happen... The problem is that the two arguments to super (current class, and actual instance) are *both* required; you can't fake the first using self.__class__. But you can't refer to the current class inside the decorator, because it doesn't exist yet. You could use the decorator to just "mark" the function to be chained, and then -with the help of a metaclass- do the actual decoration when the class is created. def chain(meth): """Mark a method to be "chained" later""" meth.chained = True return meth def chain_impl(cls, meth): """The original decorator by SD'A""" def f(self, *args, **kwargs): result = meth(self, *args, **kwargs) S = super(cls, self) getattr(S, meth.__name__)(*args, **kwargs) return result f.__name__ = "chained_" + meth.__name__ return f class ChainedType(type): def __new__(meta, name, bases, dic): cls = super(ChainedType, meta).__new__(meta, name, bases, dic) # replace functions marked "to be chained" with its decorated version for name, value in dic.iteritems(): if getattr(value, 'chained', False): setattr(cls, name, chain_impl(cls, value)) return cls class A(object): __metaclass__ = ChainedType def foo(self, x): print "I am %s" % self return x class B(A): @chain def foo(self, x): print "This is B!!!" return x + 1 class C(B): @chain def foo(self, x): print "This is C!!!" return x + 2 py> a = A() py> a.foo(5) I am <__main__.A object at 0x00A3C690> 5 py> b = B() py> b.foo(5) This is B!!! I am <__main__.B object at 0x00A3CA90> 6 py> c = C() py> c.foo(5) This is C!!! This is B!!! I am <__main__.C object at 0x00A3C830> 7 The approach above tries to stay close to the chain decorator as originally posted. There are other ways that you can search for in the Python Cookbook. -- Gabriel Genellina -- http://mail.python.org/mailman/listinfo/python-list