How to change the base class in Python - python

Say I have following
Class A(object):
base Functions
Class B (A):
some useful functions
Class C(object)
req base functions
Now I want to create a class which has all the functions from B but instead of functions from A refers to functions from C.
Something like
Class D(B,C)
and when B calls super it should look in C instead of A
The way that I am achieving it now is copy pasting the whole class B and just inheriting from C instead of A.
Is there a better way to solve this problem?
Composition can surely solve the problem, but Class B is already in heavy use so I don't want to change it.

Change the __bases__ attribute of B class.
Well, it's ugly but it works:
class A(object):
def f(self):
print("A.f()")
class B (A):
def g(self):
print("B.g()", end=": ")
super(B, self).f()
class C(object):
def f(self):
print("C.f()")
B.__bases__ = (C,)
b = B()
b.g()
You get:
B.g(): C.f()
You can use fudge.patch to do it during your unit test.
Note that your question is a duplicate of How to dynamically change base class of instances at runtime?

Related

Converting a subclass instance into its parent class instance

Let's say I have 2 classes A and B, where B inherits from A. B overrides some methods of A and B have a couple more attributes. Once I created an object b of type B, is it possible to convert it into the type A and only A ? This is to get the primitive behavior of the methods
I don't know how safe it is, but you can reassign the __class__ attribute of the object.
class A:
def f(self):
print("A")
class B(A):
def f(self):
print("B")
b = B()
b.f() # prints B
b.__class__ = A
b.f() # prints A
This only changes the class of the object, it doesn't update any of the attributes. In Python, attributes are added dynamically to objects, and nothing intrinsically links them to specific classes, so there's no way to automatically update the attributes if you change the class.

What is the Diamond Problem in Python and why its not appear in python2?

I got this code:
class A:
pass
class B(A):
pass
class C(A):
pass
class D(A,B):
pass
d = D()
In Python3 i get a MRO Error. I mean it appears because the Diamond Problem. In Python2 its no Problem. Why is this the case, and what is this Diamond Problem exactly ?
This is not the diamond problem!
The diamond problem occurs when two classes have a common ancestor, and another class has both those classes as base classes, for example:
class A:
def do_thing(self):
print('From A')
class B(A):
def do_thing(self):
print('From B')
class C(A):
def do_thing(self):
print('From C')
class D(B, C):
pass
d = D()
d.do_thing()
In some languages, because of how inheritance is implemented, when you call d.do_thing(), it is ambiguous whether you actually want the overridden do_thing from B, or the one from C.
Python doesn't have this problem because of the method resolution order. Briefly, when you inherit from multiple classes, if their method names conflict, the first one named takes precedence. Since we have specified D(B, C), B.do_thing is called before C.do_thing.
That is also why you get that problem. Consider this: since B inherits from A in your example, B's methods will come before A's. Say we have another class, B_derived, that inherits from B. The method resolution order will then be as follows:
B_derived -> B -> A
Now, we have D in the place of B_derived, therefore we can substitute it in to get this:
D -> B -> A
However, note that you have also specified that D inherits from A before B, and by the rule above, A must also come before B in the method resolution order. That means we get an inconsistent chain:
D -> A -> B -> A
This, and not the diamond problem, is why you get an error.
(See also this answer).

How can I ensure that a method is called (once, if present) for every class in a hierarchy?

I have a class hierarchy in which subclasses may optionally define a method with a given name, say do_it, and want to write a function, say do_all, in the base class that ensures that each such method will be executed, in order of class hierarchy. The closest I can get to achieving this is something like:
class A(object):
def do_it(self):
print 'Do A'
def do_all(self):
# Better, from comments and answers: vars(type(self))
for c in reversed(self.__class__.__mro__[:-1]):
c.do_it(self)
class B(A):
def do_it(self):
print 'Do B'
class C(B):
def no_do_it(self):
pass
class D(C):
def do_it(self):
print 'Do D'
This almost works as intended, for example B().do_all() gives
Do A
Do B
But it results in a duplicate call to Bs do_it for all classes descended from it. For example D().do_all() gives
Do A
Do B
Do B
Do D
How can I avoid the duplicate call to a parent's do_it from classes that do not implement it? Is this even the right way to achieve what I'm trying to do?
You can check whether the function has already been seen:
def do_all(self):
seen = set()
for c in reversed(self.__class__.__mro__[:-1]):
if c.do_it not in seen:
seen.add(c.do_it)
c.do_it(self)
Note that in Python 2 you'll need to extract the function from the unbound method, as c.do_it.__func__ (or use six.get_unbound_function).
An alternative is to examine __dict__:
def do_all(self):
for c in reversed(self.__class__.__mro__[:-1]):
if 'do_it' in c.__dict__:
c.do_it(self)

classmethod as constructor and inheritance

The problem is quite simple. If a class B inherit a class A and wants to override a ´classmethod´ that is used as a constructor (I guess you call that a "factory method"). The problem is that B.classmethod will want to reuse A.classmethod, but then it will have to create an instance of the class A, while it subclasses the class A - since, as a classmethod, it has no self. And then, it doesn't seem the right way to design that.
I did the example trivial, I do more complicate stuff by reading numpy arrays, etc. But I guess there is no loss of information here.
class A:
def __init__(self, a):
self.el1 = a
#classmethod
def from_csv(cls, csv_file):
a = read_csv(csv_file)
return cls(a)
#classmethod
def from_hdf5 ...
class B(A):
def __init__(self, a, b)
A.(self, a)
self.el2 = b
#classmethod
def from_csv(cls, csv_file):
A_ = A.from_csv(csv_file) #instance of A created in B(A)
b = [a_*2 for a_ in A.el]
return cls(A.el, b)
Is there a pythonic way to deal with that?
After doing some different trials. My conclusion is that you should override a classmethod without reusing the code inside. So the best way I found, for my particular problem, is to make the classmethod as simply as possible and put the code I want to reuse in another method, static in my case, since the classmethod is a constructor.
One easy solution would be to have class B's __init__ method have a default value for its b parameter. This would let the cls(a) call made by A.from_csv work when it is inherited. If the default is used, the __init__ method could calculate a value to store from a (as you do in B.from_csv now).
class B(A):
def __init__(self, a, b=None):
super().__init__(a) # use super(B, self).__init__(a) if you're in Python 2
self.el2 = b if b is not None else [i*2 for i in a]
# don't override from_csv, B.from_csv will already return a B instance!

Python inheritance

My base code looks like this:
class C1(object):
def f(self):
return 2*self.g()
def g(self):
return 2
class C2(C1):
def f(self):
return 3*self.g()
class C3(C1):
def g(self):
return 5
class C4(C3):
def f(self):
return 7*self.g()
obj1 = C1()
obj2 = C2()
obj3 = C3()
obj4 = C4()
Now my question is the following: I need to write three assignment statements that do the following:
assign the calling list for obj2.f() to the variable obj2_calls
assign the calling list for obj3.f() to the variable obj3_calls
assign the calling list for obj4.f() to the variable obj4_calls
Calling list being for example, when obj1.f() is called, the f method of C1 is called which calls the g method of C1. This could be represented as a calling list of the form ['C1.f', 'C1.g']
I don't quite know the proper way to write the assignment statements and I desperately want to help out my friend with her stuff.
If you could just show me how to properly right out the first assignment statement, I'm sure I could figure out the rest.
The key insight is that if a method is not defined for a class, it will default to use the method of a class that the class inherits.
Thus, ask yourself what 'obj2.f()' will do.
What class is obj2? It is C2.
Is there an f method defined for class C2? Yes, there is. So the method C2.f is called.
The C2.f method calls self.g, which means it looks for C2.g. Is there a 'C2.g' method? No, so we have to go to the class that C2 inherits from. The line class C2(C1) tells us that it is inherited from the class C1, so it will call the method C1.g.
Those are the steps to get the first calling list; the rest are up to you.

Categories

Resources