Re: using super



En Mon, 31 Dec 2007 12:08:43 -0200, Steven D'Aprano <steve@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> 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

.



Relevant Pages

  • Re: Getting rid of "self."
    ... def __init__: ... > basis of information available at the time the decorator executes. ... I am content with declaring them like the selfless ... foo = _foo ...
    (comp.lang.python)
  • Re: python-style decorators
    ... def tak ... decorator at the bottom makes it easy to miss, ...
    (comp.lang.ruby)
  • Re: Docorator Disected
    ... >>a nested fee as if it existed ready to call in the same way as foo. ... >>exist that way until the fee def is EXECUTED, ... is obscuring normal decorator functionality. ...
    (comp.lang.python)
  • Argument Decorators Enhancement?
    ... Guido has proposed a syntax for type annotations in Python-3000. ... to a decorator than a static type declaration. ... def foo__: # original function ... def bar(@int x, @float y) @float: ...
    (comp.lang.python)
  • Re: elements of decorator syntax suggestions
    ... >> Proposals also differ on exactly where the decorator declaration ... >def functionname. ... >> proposals that might be accepted must explain how this can be done. ... >def func(): ...
    (comp.lang.python)