Python dynamic multiple inheritance - python

I want to choose from which class I inherit at runtime, either class A or B, depending on an argument to my init function in AorB. I already tried the following code, but the methods are not overloaded the way I want them to be overloaded: AorB("B").a() returns A.a() instead of B.a(). How do I choose from which class I inherit at runtime?
Update:
From the reaction below I tried the following code. Now I want to inherit AorB in class C, which doesn't work yet:
class A(object):
def a(self):
return "I'm A.a"
def b(self):
return "I'm A.b"
class B(object):
def a(self):
return "I'm B.a"
def c(self):
return "I'm B.c"
def AorB(classname, cache={}):
if not classname in cache:
Base = globals()[classname]
class AorB(Base):
def __init__(self):
print(classname)
Base.__init__(self)
cache[classname] = AorB
return cache[classname]()
class C(AorB):
def __init__(self, classname):
AorB.__init__(classname)
if __name__ == "__main__":
a = AorB("A")
print("A.a:", a.a())
print("A.b:", a.b())
b = AorB("B")
print("B.a:", b.a())
print("B.c:", b.c())
c = C("B")
print("C.a:", c.a())
print("C.c:", c.c())
yields
Traceback (most recent call last):
File "classtest.py", line 28, in <module>
class C(AorB):
TypeError: Error when calling the metaclass bases
function() argument 1 must be code, not str
instead of:
A
('A.a:', "I'm A.a")
('A.b:', "I'm A.b")
B
('B.a:', "I'm B.a")
('B.c:', "I'm B.c")
B
('C.a:', "I'm B.a")
('C.c:', "I'm B.c")

class A(object):
def a(self):
return "I'm A.a"
def b(self):
return "I'm A.b"
class B(object):
def a(self):
return "I'm B.a"
def c(self):
return "I'm B.c"
def make_AorB(Base, classname):
class AorB(Base):
def __init__(self):
print(classname)
Base.__init__(self)
return AorB
def make_C(Base, classname):
class C(Base):
def __init__(self):
Base.__init__(self)
def d(self):
return "I'm C.d"
return C
def make_factory(getbase, make_cls):
def factory(classname):
if not classname in factory.cache:
Base = getbase(classname)
factory.cache[classname] = make_cls(Base, classname)
return factory.cache[classname]()
factory.cache = {}
return factory
AorB = make_factory(lambda classname: globals()[classname], make_AorB)
C = make_factory(lambda classname: AorB.cache[classname], make_C)
if __name__ == "__main__":
a = AorB("A")
print(a.__class__, a.__class__.__bases__)
print("A.a:", a.a())
print("A.b:", a.b())
b = AorB("B")
print(b.__class__, b.__class__.__bases__)
print("B.a:", b.a())
print("B.c:", b.c())
c = C("B")
print(c.__class__, c.__class__.__bases__)
print("C.a:", c.a())
print("C.c:", c.c())
print("C.d:", c.d())
yields
A
(<class '__main__.AorB'>, (<class '__main__.A'>,))
('A.a:', "I'm A.a")
('A.b:', "I'm A.b")
B
(<class '__main__.AorB'>, (<class '__main__.B'>,))
('B.a:', "I'm B.a")
('B.c:', "I'm B.c")
B
(<class '__main__.C'>, (<class '__main__.AorB'>,))
('C.a:', "I'm B.a")
('C.c:', "I'm B.c")
('C.d:', "I'm C.d")

I'm not 100% sure (of your use-case), but you may be able to use the variation of type to do something like the following (where something is some conditional):
def produce_C(kls, *args, **kwdargs):
return type('C', (globals()[kls],), {})(*args, **kwdargs)
Which is going to confuse the type system though... (possibly amend the class name to be C_from_A or C_from_B - but ugh)

Here is the problem with your code (after the update)
C can't inherit from AorB, which is a function:
class C(AorB):
def __init__(self, classname):
AorB.__init__(classname)
Since you want to bass the baseclass in a call to C, you can just make C a
function that calls AorB in turn:
def C(basename):
return AorB(basename)

Related

dynamic method binding in python

I have the following two classes A and B. How do I make the do_someting() method call the overriden method, some_method(), in B. Is this doable in Python?
class A:
#staticmethod
def some_method()
# pass
return
#classmethod
def do_something():
A.some_method()
...
return
class B(A):
#staticmethod
def some_method()
# how does do_something call here?
return
#classmethod
def run()
B.do_something()
return
It's pretty simple, just make sure to fix your colons pass in self and cls:
class A:
#staticmethod
def some_method():
# pass
return
#classmethod
def do_something(cls):
cls.some_method()
return
class B(A):
#staticmethod
def some_method():
print("I did stuff!")
return
#classmethod
def run(cls):
B.do_something()
return
k = B()
k.run()
>>>"I did stuff!"
And if you want to call the old do_something (the one in class A) from class B, just pass in the appropriate class. In class B:
#classmethod
def run(cls):
A.do_something()
return

encapsulating class calls/modifies things in the dir of original class

I have a class A encapsulating a class B instance and additional stuff. The following is a toy example.
class B(object):
def __init__(self):
self.b = 2
def square(self):
return self.b * self.b
class A(object):
def __init__(self, x):
self.b = B()
a = A(1)
print(a.b.square())
Any time an A instance wants to call a method in B, I always need to do things like 'a.b'. My hope is to get rid of '.b' for user convenience. The following codes do the job.
class B(object):
def __init__(self):
self.b = 2
def square(self):
return self.b * self.b
class A(object):
def __init__(self, x):
self.b = B()
def square(self):
return self.b.square()
a = A(1)
print(a.square())
The problem is that class B is from outside library and there are lots of and different types of things in the dir. I couldn't do it one by one manually like above. Any magical ways to handle that?
Any magical ways to handle that?
It's python, of course there are! You can use __getattr__ function to proxy unknown calls to b:
class B(object):
def shadowed(self):
print('B.shadowed')
def unshadowed(self):
print('B.unshadowed')
class A(object):
def __init__(self):
self._b = B()
def shadowed(self):
print('A.shadowed')
def __getattr__(self, name):
return getattr(self._b, name)
test = A()
test.shadowed()
test.unshadowed()
test.unknown()
Result:
A.shadowed
B.unshadowed
Traceback (most recent call last):
File "/Users/Andrew/Desktop/test.py", line 23, in <module>
test.unknown()
File "/Users/Andrew/Desktop/test.py", line 17, in __getattr__
return getattr(self._b, name)
AttributeError: 'B' object has no attribute 'unknown'
__getattr__ is called when the object doesn't have attribute that's being asked for.

Call grandparent method in grand child class

Sorry, may be this is silly question, but its very confusing to me. Let's suppose we have the following classes:
class A():
def say(self):
print("A")
class B(A):
def say(self):
print("B")
class C(B):
def say(self,*args, **kwargs):
return super(C, self).say(*args, **kwargs)
I am accessing parent method in child, and it prints B, but I want to access method from class A as we are getting access from class B.
I know we can add super in class B, but I don't want to modify class B. so is there any option to get method from A directly in class C?
You can by calling A.say(self) like this:
class A():
def say(self):
print("A")
class B(A):
def say(self):
print("B")
class C(B):
def say(self):
A.say(self)
B.say(self)
print("C")
Then to test it out from a terminal:
>>> a = A()
>>> a.say()
A
>>> b = B()
>>> b.say()
B
>>> c = C()
>>> c.say()
A
B
C
Note: I dropped the args and kwargs because the A and B classes didn't use those arguments. If you wanted to make say take those all the way up though simply call A.say(self, *args, **kwargs) and if A.say returns something you can return it too

Python: nested class with static method fails

What is wrong with the following code?
class A:
def A_M(self): pass
class B:
#staticmethod
def C(): super(B).A_M()
error (Python 2.7.3):
>>> a = A()
>>> a.B.C()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "..x.py", line 36, in C
def C(): super(B).A_M()
NameError: global name 'B' is not defined
Edit:
the solution was simple as this:
class A:
def A_M(self): pass
class B:
#staticmethod
def C(): A().A_M() #use of A() instead of supper, etc.
Important Note that there is an issue with this solution. If you change the name of super class (i.e. A) then you will have to update all uses inside itself as A :)).
class A(object):
def foo(self):
print('foo')
#staticmethod
def bar():
print('bar')
class B(object):
#staticmethod
def bar(obj):
# A.foo is not staticmethod, you can't use A.foo(),
# you need an instance.
# You also can't use super here to get A,
# because B is not subclass of A.
obj.foo()
A.foo(obj) # the same as obj.foo()
# A.bar is static, you can use it without an object.
A.bar()
class B(A):
def foo(self):
# Again, B.foo shouldn't be a staticmethod, because A.foo isn't.
super(B, self).foo()
#staticmethod
def bar():
# You have to use super(type, type) if you don't have an instance.
super(B, B).bar()
a, b = A(), B()
a.B.bar(a)
b.foo()
B.bar()
See this for details on super(B, B).
You need to use a fully-qualified name. Also, in python 2.7, you need to use (object), else super(A.B) will give TypeError: must be type, not classobj
class A(object):
def A_M(self):
pass
class B(object):
#staticmethod
def C():
super(A.B).A_M()
Finally, super(A.B) is essentially object here. Did you mean for B to inherit from A? Or were you simply looking for A.A_M()?
A latecommer, to just encapsulate B in A the easy way is this:
class A:
def A_M(self):
return "hi"
class B:
#staticmethod
def C():
return A().A_M()
a = A()
print a.B().C()
Not sure this is what you need, but the question was still unsolved, so I guessed.

Multiple inheritance problem in Python!

Why does c.print_a() output 'B'?
class A(object):
def __init__(self):
self.some_name = 'A'
def print_a(self):
print self.some_name
class B(object):
def __init__(self):
self.some_name = 'B'
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
if __name__ == '__main__':
c = C()
c.print_a()
class A(object):
def __init__(self, some_name='A'):
self.some_name = some_name
def print_a(self):
print self.some_name
class B(object):
def __init__(self, some_name='B'):
self.some_name = some_name
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
A.__init__(self, some_name='AAAAA')
B.__init__(self, some_name='BBBBB')
if __name__ == '__main__':
c = C()
c.print_a()
You only have a single object here; the some_name property is shared between methods from all inherited classes. You call A.__init__, which sets it to A, then B.__init__, which changes it to B.
Also note that you're calling base methods incorrectly; use super:
class A(object):
def __init__(self):
self.some_name = 'A'
super(A, self).__init__()
def print_a(self):
print self.some_name
class B(object):
def __init__(self):
self.some_name = 'B'
super(B, self).__init__()
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
super(C, self).__init__()
if __name__ == '__main__':
c = C()
c.print_a()
There's only one self, and you're overwriting its some_name in B.__init__. Maybe you're used to C++, where there would be two separate fields, A.some_name and B.some_name. This concept doesn't apply to Python, where attributes are created dynamically on assignment.
Say you want C to set names for some objects of types A and B and later calling some print_a and print_b methods on objects of type C get these names back ?
You can get this type of behavior using C++ inheritance model, but python model is very different. Only one object with one set of fields. If you want the C++ behavior, the simplest way is probably to declare subobjects (and it looks like a common abuse of inheritance over composition).
Looks like you are trying to do something like below:
class Printable(object):
def __init__(self, name):
self.name = name
def myprint(self):
print self.name
class C(object):
def __init__(self):
self.a = Printable('A')
self.b = Printable('B')
def print_a(self):
self.a.myprint()
def print_b(self):
self.a.myprint()
if __name__ == '__main__':
c = C()
c.print_a()

Categories