Creating new types and invoking super

G

Guilherme Polo

Hello,

Before starting, let me show some sample codes so I can explain:

class A(object):
def __init__(self):
super(A, self).__init__()

x = type("X", (A, ), {})()

This works fine, but suppose I have several classes like A and I would
like to create a decorator to call super. First I tried this:

def init(func):
def _init(inst):
super(inst.__class__, inst).__init__()
func(inst)

return _init

class A(object):
@init
def __init__(self): pass

This works when I create a instance by doing A(), but I get
"RuntimeError: maximum recursion depth exceeded" when I create a new
type doing type("X", (A, ), {}) and then create an instance of it.
To "solve" this problem, I changed the init function to this then:

def init(func):
def _init(inst):
super(inst.__class__.__mro__[-2], inst).__init__()
func(inst)

return _init

It works if A is a direct subclass of object, if it is not I have to
adapt the index [-2].
So, is there a better way to do this ?
 
A

Arnaud Delobelle

Hello,
Hi
[...]
First I tried this:

def init(func):
    def _init(inst):
        super(inst.__class__, inst).__init__()
        func(inst)

    return _init

class A(object):
    @init
    def __init__(self): pass

This kind of approach can't work, you need to call super(A, obj).
super(type(obj), obj) is pointless, it defeats the whole purpose of
the mro!

The only way I can think of would be to create a metaclass, but I
don't think it's worth it. super(A, obj).__init__() isn't that bad!
 
G

Guilherme Polo

2008/1/23 said:
Hello,
Hi
[...]
First I tried this:

def init(func):
def _init(inst):
super(inst.__class__, inst).__init__()
func(inst)

return _init

class A(object):
@init
def __init__(self): pass

This kind of approach can't work, you need to call super(A, obj).
super(type(obj), obj) is pointless, it defeats the whole purpose of
the mro!

Yeh, as shown in the next examples in the previous email. Using a
decorator for that doesn't sound useful at all, was just trying
something different ;) I will stick to the no-decorator option.
The only way I can think of would be to create a metaclass, but I
don't think it's worth it. super(A, obj).__init__() isn't that bad!

Metaclass doesn't apply here because metaclass is related to
class-construction. This is related to instance initialization, and
I'm creating the types as the user asks.
 
G

Guilherme Polo

2008/1/23 said:
2008/1/23 said:
Hello,
Hi
[...]
First I tried this:

def init(func):
def _init(inst):
super(inst.__class__, inst).__init__()
func(inst)

return _init

class A(object):
@init
def __init__(self): pass

This kind of approach can't work, you need to call super(A, obj).
super(type(obj), obj) is pointless, it defeats the whole purpose of
the mro!

Yeh, as shown in the next examples in the previous email. Using a
decorator for that doesn't sound useful at all, was just trying
something different ;) I will stick to the no-decorator option.
The only way I can think of would be to create a metaclass, but I
don't think it's worth it. super(A, obj).__init__() isn't that bad!

Metaclass doesn't apply here because metaclass is related to
class-construction. This is related to instance initialization, and
I'm creating the types as the user asks.

Oops, actually it can be done. But I am not going to stick to it, just
did a sample here that "solves" for a not so deep structure:

def init(func):
def _init(cls):
if hasattr(cls, "myclass"):
super(cls.myclass, cls).__init__()
else:
super(cls.__class__, cls).__init__()
func(cls)

return _init

class M(type):
def __new__(cls, classname, bases, classdict):
if not len(classdict):
if 'myclass' in bases[0].__dict__:
classdict['myclass'] = bases[0].__dict__['myclass']
else:
classdict['myclass'] = bases[0]


return type.__new__(cls, classname, bases, classdict)

class Y(object):
__metaclass__ = M

class X(Y):
@init
def __init__(self):
print "X"

X()
y = type("Z", (X, ), {})
w = type("W", (y, ), {})
y()
w()
 
A

Arnaud Delobelle

Metaclass doesn't apply here because metaclass is related to
class-construction. This is related to instance initialization, and
I'm creating the types as the user asks.

Not completely clear to me what you want but here is a 'proof of
concept':

==========

class callsuper(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, cls=None):
def newfunc(*args, **kwargs):
super(self.cls, obj).__init__()
return self.f(obj, *args, **kwargs)
return newfunc

class Type(type):
def __init__(self, name, bases, attrs):
for attrname, attr in attrs.iteritems():
if isinstance(attr, callsuper):
attr.cls = self

class A:
__metaclass__ = Type
def __init__(self):
print "init A"

class B(A):
@callsuper
def __init__(self):
print "init B"

==========
init A
init B
 
G

Guilherme Polo

2008/1/23 said:
Not completely clear to me what you want but here is a 'proof of
concept':

==========

class callsuper(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, cls=None):
def newfunc(*args, **kwargs):
super(self.cls, obj).__init__()
return self.f(obj, *args, **kwargs)
return newfunc

class Type(type):
def __init__(self, name, bases, attrs):
for attrname, attr in attrs.iteritems():
if isinstance(attr, callsuper):
attr.cls = self

class A:
__metaclass__ = Type
def __init__(self):
print "init A"

class B(A):
@callsuper
def __init__(self):
print "init B"

==========

init A
init B

Thanks for this concept, works better than mine :)
 
A

Arnaud Delobelle

class callsuper(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, obj, cls=None):
        def newfunc(*args, **kwargs):
            super(self.cls, obj).__init__()

Change this line to:
getattr(super.cls, obj), self.f.__name__)()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,042
Latest member
icassiem

Latest Threads

Top