How to define a new subclass that only changes the parent class? - python

I have the following simplified class structure
class A():
def foo(self):
self.bar()
def bar(self):
print("A bar")
class B(A):
def bar(self):
print("B bar")
class C(A):
def bar(self):
print("C bar")
Now I also have a modified version of A
class ModA():
def foo(self):
print("hi")
self.bar()
I now also want a additional versions of B and C that have ModA as parent class instead of A.
class ModB(ModA):
def bar(self):
print("B bar")
class ModC(ModA):
def bar(self):
print("C bar")
How do I define ModB and ModC without duplicating their entire definition except for the first line that defines the parents?

It is impossible to answer without knowing what your "slight changes" might be, but in general, look at multi-inheritance - class ModB(ModA, B): might be what you need.
class ModB(ModA, B):
pass
>>> b = ModB()
>>> b.foo()
hi
B bar

Based on your toy example here is one way to do it.
class FooBase:
def foo(self):
self.bar()
class FooMod:
def foo(self):
print("hi")
self.bar()
class A(FooBase):
def bar(self):
print("A bar")
class B(FooBase):
def bar(self):
print("B bar")
class C(FooBase):
def bar(self):
print("C bar")
class ModA(FooMod,A):
pass
class ModB(FooMod,B):
pass
class ModC(FooMod,C):
pass
class BadModA(A,FooMod):
pass
for thing in [A,B,C,ModA,ModB,ModC,BadModA]:
thing = thing()
print(thing.foo())
print('**********')
You have to be careful how you order the base classes notice BadModA doesn't work because it finds the foo method in FooBase before looking in FooMod. You can see that in their Method Resolution Order's
In [15]: ModA.__mro__
Out[15]: [__main__.ModA, __main__.FooMod, __main__.A, __main__.FooBase, object]
In [16]: BadModA.__mro__
Out[16]: (__main__.BadModA, __main__.A, __main__.FooBase, __main__.FooMod, object)
While this works it seems like you could get yourself in trouble. you always have to remember which order to use - maybe someone will comment.
Here is another way, it flattens the structure out a bit, five bases and you mix them up
class FooBase:
def foo(self):
self.bar()
class FooMod:
def foo(self):
print("hi")
self.bar()
class Abar:
def bar(self):
print("A bar")
class Bbar:
def bar(self):
print("B bar")
class Cbar():
def bar(self):
print("C bar")
class A(FooBase,Abar):
pass
class B(FooBase,Bbar):
pass
class C(FooBase,Cbar):
pass
class ModA(FooMod,Abar):
pass
class ModB(FooMod,Bbar):
pass
class ModC(FooMod,Cbar):
pass

Related

super() of python2.7 skips direct parents?

When I tried to call the bar() of class B from class C, which is a direct subclass of B, it turned out that the bar() of class A was called. But I explicitly required that the B version should be used. How can the method be resolved to that of A?
class A(object):
def bar(self):
print('bar from A')
class B(A):
def bar(self):
print('bar from B')
class C(B):
def bar(self):
super(B, self).bar()
c = C()
# It should print "bar from B"
c.bar()
# But actually it prints "bar from A"
It's because super(sub_class, instance).method() means call the method method of the parent of sub_class on the instance instance. Since the parent of B is A, the result makes sense.
What you want is super(C, self).bar().

Fetching parent's function from parent

I override a function, but would like to get hold of the parent's function from within the parent.
>>> class a:
... def __init__(self):
... print(self.f)
... def f(self):
... pass
...
>>> class b(a):
... def __init__(self):
... super(b, self).__init__()
... def f(self):
... pass
...
>>> b()
<bound method b.f of <__main__.b object at 0x000002E297A96160>>
I'd like the printout to say a.f.
You could use name mangling to make self.__f refer to A.__f from within A's class definition.
Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls
class A:
def __init__(self):
self.__f()
def f(self):
print('A.f')
__f = f # Private copy of A's `f` method
class B(A):
def __init__(self):
super(B, self).__init__()
def f(self):
print('B.f')
b = B()
b.f()
prints
A.f
B.f
class a(object):
def __init__(self):
pass
def f(self):
print 'Parent Method...'
class b(a):
def __init__(self):
super(b, self).__init__()
a.f(self) #referance the parent class rather than the child class, because the child overrides the parent method.
self.f()
def f(self):
print "Childs Method..."
b()

How do I call a method on a specific base class in Python?

How do I call a method on a specific base class? I know that I can use super(C, self) in the below example to get automatic method resolution - but I want to be able to specify which base class's method I am calling?
class A(object):
def test(self):
print 'A'
class B(object):
def test(self):
print 'B'
class C(A,B):
def test(self):
print 'C'
Just name the "base class".
If you wanted to call say B.test from your C class:
class C(A,B):
def test(self):
B.test(self)
Example:
class A(object):
def test(self):
print 'A'
class B(object):
def test(self):
print 'B'
class C(A, B):
def test(self):
B.test(self)
c = C()
c.test()
Output:
$ python -i foo.py
B
>>>
See: Python Classes (Tutorial)

Python subclasses calling parent function

class A():
class B():
def Foo(self):
print "Hello"
class C():
def Bar(self):
print "Goodbye"
def name(self):
print "FooBar"
What I want to do is, within the Bar function is call the Foo function. How would I do that?
In Python, inner classes don't have an implicit instance of the outer class associated with them. Without such an instance, you can't call A's non-static methods from B or C.
If you do have such an instance, then simply use the dot notation:
class C():
def Bar(self):
self.a.name()
...
(where self.a is an instance of A.)
Alternatively, if A.name() can be made static, the following will also work:
class A(object):
class C():
def Bar(self):
print "Goodbye"
A.name()
#staticmethod
def name():
print "FooBar"
A.C().Bar()
You need an instance of class A to call a method.

How can I tell what class in the polymorphic hierarchy contains the method I'm about to call?

If I have:
class A():
def f(self):
print("running function, f from class A")
class B(A):
def __init__(self):
A.__init__(self)
def f(self):
print("running function, f from class B")
and I make an instance of class B and call f on it, we all know we'll see the message about "from class B." But is there a way for me to inspect my object and make sure my sub-class has overridden my method? Something like:
obj = B()
assert(not obj.f.livesIn(A))
class A():
def f(self):
print("running function, f from class A")
class B(A):
def f(self):
print("running function, f from class B")
class C(A):
pass
This shows that B.f does not equal A.f. So B must override f:
obj = B()
print(obj.__class__.f == A.f)
# False
This shows that C.f equals A.f. So C must not have overridden f:
obj = C()
print(obj.__class__.f == A.f)
# True
If you want to force the child class to override, you can raise NotImplementedError().
Doing the inspection is possible too... And I see unutbu just posted an example, so I won't repeat it. :)

Categories

Resources