Based on this answer, of how __new__
and __init__
are supposed to work in Python,
I wrote this code to dynamically define and create a new class and object.
class A(object):
def __new__(cls):
class C(cls, B):
pass
self = C()
return self
def foo(self):
print 'foo'
class B(object):
def bar(self):
print 'bar'
a = A()
a.foo()
a.bar()
Basically, because the __new__
of A returns a dynamically created C that inherits A and B, it should have an attribute bar
.
Why does C
not have a bar
attribute?
Resolve the infinite recursion:
class A(object):
def __new__(cls):
class C(cls, B):
pass
self = object.__new__(C)
return self
(Thanks to balpha for pointing out the actual question.)
Since there is no actual question in the question, I am going to take it literally:
Whats wrong doing it dynamically?
Well, it is practically unreadable, extremely opaque and non-obvious to the user of your code (that includes you in a month :P).
From my experience (quite limited, I must admit, unfortunately I don't have 20 years of programming under the belt), a need for such solutions indicates, that the class structure is not well defined, - means, there's almost always a better, more readable and less arcane way to do such things.
For example, if you really want to define base classes on the fly, you are better off using a factory function, that will return appropriate classes according to your needs.
Another take on the question:
Whats wrong doing it dynamically?
In your current implementation, it gives me a "maximum recursion depth exceeded" error. That happens, because A.__new__
calls itself from within itself indefinitely (since it inherits from itself and from B
).
10: Inside A.__new__
, "cls" is set to <class '.A'>
. Inside the constructor you define a class C
, which inherits from cls
(which is actually A
) and another class B
. Upon instantiating C
, its __new__
is called. Since it doesn't define its own __new__
, its base class' __new__
is called. The base class just happens to be A
.
20: GOTO 10
If your question is "How can I accomplish this" – this works:
class A(object):
@classmethod
def get_with_B(cls):
class C(B, cls):
pass
return C()
def foo(self):
print 'foo'
class B(object):
def bar(self):
print 'bar'
a = A.get_with_B()
a.foo()
a.bar()
If your question is "Why doesn't it work" – that's because you run into an infinite recursion when you call C()
, which leads to A.__new__
being called, which again calls C()
etc.