views:

122

answers:

2

I try define class decorator. I have problem with __init__ method in decorated class. If __init__ method invokes super the RuntimeError maximum recursion depth exceeded is raised.

Code example:

def decorate(cls):
    class NewClass(cls): pass
    return NewClass

@decorate
class Foo(object):
    def __init__(self, *args, **kwargs):
        super(Foo, self).__init__(*args, **kwargs)

What am I doing wrong?

Thanks, Michał

Edit 1

Thanks to Mike Boers answer I realized that correct question is what should I do to achive that super(Foo, self) point to proper class.

I have also two limitation. I want invoke Foo.__init__ method and I can't change Foo class definition.

Edit 2

I have solved this problem. I modify decorator function body. I don't return new class. Instead of I wrap methods of orginal class.

+3  A: 

Remember that a decorator is simply syntactic sugar for:

>>> Foo = decorate(Foo)

So in this case the name Foo actually refers to the NewClass class. Within the Foo.__init__ method you are in fact asking for the super __init__ of NewClass, which is Foo.__init__ (which is what is currently running).

Thus, your Foo.__init__ keeps receiving its own __init__ to call, and you end up in an infinite recursion.

Mike Boers
A: 

You need to override NewClass.__init__ to prevent recursion, because NewClass.__init__ is Foo.__init__ and it keeps calling itself.

def decorate(cls):
    class NewClass(cls):
        def __init__(self):
            pass
    return NewClass

New idea:

How about not subclassing it? Maybe monkey patching is your friend?

def decorate(cls):
    old_do_something = cls.do_something
    def new_do_something(self):
        print "decorated",
        old_do_something(self)

    cls.do_something = new_do_something
    return cls

@decorate
class Foo(object):
    def __init__(self, *args, **kwargs):
        super(Foo, self).__init__(*args, **kwargs)

    def do_something(self):
        print "Foo"

f = Foo()
f.do_something()
petraszd
Ok, but I want execute Foo.__init__ method. I also can't edit Foo class definition.
Michał Lula
Yes, it is working fine.
Michał Lula