Calling all childs of a Parent class in python - python

Lets say we have a parent class like the following
class P():
#staticmethod
def sth():
pass
And I create several child classes that define the sth() method, something like the following
class P_a(P):
#staticmethod
def sth():
#Implementation a
class P_b(P):
#staticmethod
def sth():
#Implementation b
class P_c(P):
#staticmethod
def sth():
#Implementation c
How would I call the sth() method of all the child classes?
At the moment, I'm just adding the classes to a list and, based on a for loop, calling the sth() method on all of them. Because that method is implemented in every class, all of them understand it and know if they should take care of the task or not (Not sure if this is the best way of doing this tho)
Is it there a way of basically calling the sth() method of all the classes that inherit from class P?

Try this:
class P:
subclasses = []
def __init_subclass__(cls, *args, **kwargs) -> None:
P.subclasses.append(cls)
#staticmethod
def sth():
print("Base Implementation")
#classmethod
def call_all_sth(cls):
cls.sth()
for klass in cls.subclasses:
klass.sth()
class P_a(P):
#staticmethod
def sth():
print("Implementation a")
class P_b(P):
#staticmethod
def sth():
print("Implementation b")
class P_c(P):
#staticmethod
def sth():
print("Implementation c")
P.call_all_sth()
Output is:
Base Implementation
Implementation a
Implementation b
Implementation c

Related

How can I dynamically refer to a child class from the super class in Python?

Consider this situation:
class Foo(ABC):
#abstractmethod
def some_method(self):
return
class Bar(Foo):
def some_method(self, param):
# do stuff
return
class Baz(Foo):
def some_method(self, param):
# do stuff differently
return
def do_something_with_obj(some_obj: Foo):
some_param = 'stuff'
some_obj.some_method(some_param)
def main(cond):
if cond:
obj = Bar()
else:
obj = Baz()
do_something_with_obj(obj)
I get an Expected 0 positional arguments error when I try to call some_method() under the do_something_with_obj() method. Of course, this is because I'm essentially calling the abstract method. My question is, how can I dynamically refer to the child class method since I have to choose the right child class based on some condition beforehand?

How to override in multiple classes without code duplication (Python)

I am having a parent class A with few classes inheriting from it (B,C,...).
I have some function is_class_A that is implemented in A, and I want to override it in B and C in the same way.
Let say:
class A:
def is_class_A():
print("We are in class A")
class B(A):
def is_class_A():
print("Nope")
class C(A):
def is_class_A():
print("Nope")
Take in mind both functions that implement in class A and in the others, are long, and more complicate.
2 solutions I came in my mind to avoid the duplication in B, C implementation:
Using in class C:
def is_class_A():
return B.is_class_A()
I am not sure how this will be functional, because an object of C is not an object of B. And I don't pass here any self, so I don't see how this will work, maybe something similar can?
Next solution is using another heritage:
class C(B)
This won't work always, since not always possible (if they have different attributes) and might not fit the design purpose.
My best attempt so far is to use another class:
class BC(A):
def is_class_A():
print("Nope")
class B(BC):
pass
class C(BC):
pass
What do you think? Some more ideas? Maybe something more technical that won't involve with the program design?
Thanks.
One option is to define the alternate method once at the global scope, then do direct class attribute assignment.
class A:
def is_class_A(self):
print("We are in class A")
def alt_is_class_A(self):
print("Nope")
class B(A):
is_class_A = alt_is_class_A
class C(A):
is_class_A = alt_is_class_A
class D(A):
pass # No override
The assignment could also be handled by a decorator:
def mod_it(cls):
cls.is_class_A = alt_is_class_A
#mod_it
class B(A):
pass
#mod_it
class C(A):
pass
# No override
class D(A):
pass
or via A.__init_subclass__:
class A:
def is_class_A(self):
print("We are in class A")
def __init_subclass__(cls, is_class_A=None):
super().__init_subclass__()
if is_class_A is not None:
cls.is_class_A = is_class_A
def alt_is_class_A(self):
print("Nope")
class B(A, is_class_A=alt_is_class_A):
pass
class C(A, is_class_A=alt_is_class_A):
pass
# No override
class D(A):
pass

I want to call parent class method which is overridden in child class through child class object in Python

class abc():
def xyz(self):
print("Class abc")
class foo(abc):
def xyz(self):
print("class foo")
x = foo()
I want to call xyz() of the parent class, something like;
x.super().xyz()
With single inheritance like this it's easiest in my opinion to call the method through the class, and pass self explicitly:
abc.xyz(x)
Using super to be more generic this would become (though I cannot think of a good use case):
super(type(x), x).xyz()
Which returns a super object that can be thought of as the parent class but with the child as self.
If you want something exactly like your syntax, just provide a super method for your class (your abc class, so everyone inheriting will have it):
def super(self):
return super(type(self), self)
and now x.super().xyz() will work. It will break though if you make a class inheriting from foo, since you will only be able to go one level up (i.e. back to foo).
There is no "through the object" way I know of to access hidden methods.
Just for kicks, here is a more robust version allowing chaining super calls using a dedicated class keeping tracks of super calls:
class Super:
def __init__(self, obj, counter=0):
self.obj = obj
self.counter = counter
def super(self):
return Super(self.obj, self.counter+1)
def __getattr__(self, att):
return getattr(super(type(self.obj).mro()[self.counter], self.obj), att)
class abc():
def xyz(self):
print("Class abc", type(self))
def super(self):
return Super(self)
class foo(abc):
def xyz(self):
print("class foo")
class buzz(foo):
def xyz(self):
print("class buzz")
buzz().super().xyz()
buzz().super().super().xyz()
results in
class foo
Class abc

Handling custom __new__() and __del__() with inheritance

When I derive a class in Python, I need to call the Base.__init__(self) from the derived __init__(self) function like
class Base(object):
def __init__(self):
pass
class Der(Base):
def __init__(self) :
Base.__init__(self)
Do I need to do the same for __new__(self) and __del__(self) functions like
class Base(object):
def __new__(self):
pass
def __init__(self):
pass
def __del__(self) :
pass
class Der(Base):
def __new__(self):
Base.__new__(self)
def __init__(self) :
Base.__init__(self)
def __del__(self) :
Base.__del__(self)
I am wondering because nothing seems to go WRONG if I don't do that.
I am sure that python gc will take care, but is there anything I need to be worried about if I don't call them from Derived chain
The usage of __init__() and __del() is straightforward but not the __new()__
Since __new()__ returns an instance of the class, we need to call super().__new()__ till the object chain as given below
class Base(object):
def __new__(self):
return super().__new__(self)
class Derive(Base):
def __new__(self):
return super().__new__(self);
The __del()__ can be using similar to __init()__, calling Base.__del()__ is not mandatory unless and until some cleanup is required in base __del() function.
The correct way of writing the code asked in the question is
class Base(object):
def __new__(self):
return super().__new__(self)
def __init__(self):
self.Value = 200
def __del__(self):
pass
class Derive(Base):
def __new__(self):
return super().__new__(self);
def __init__(self):
Base.__init__(self)
def __del__(self):
Base.__del__(self)
It's always better not to implement __new()__ and __del()__ unless we really need it

Python inheritance - One constructor that calls a method that's overriden in child classes, which method is used?

I'm writing a class in python that has multiple subclasses in it I have:
class Parent:
def __init__(self, parameters):
self.MethodA(parameters)
def MethodA(parameters):
doStuff
class child1(Parent):
def MethodA(parameters):
doOtherStuff
Which method will be used when I make an object of type child1?
Try it and see:
class Parent(object):
def __init__(self, params):
self.method(params)
def method(self, params):
print "Parent's method called with", params
class Child(Parent):
def method(self, params):
print "Child's method called with", params
Child('foo')
outputs:
Child's method called with foo
child1.MethodA() would be called. Methods in most dynamic languages are essentially always virtual since the lookup of self is done at runtime.
It can be usefull for you - method resolution order.
All methods in Python are effectively virtual.
>>> class Parent(object):
def __init__(self):
self.MethodA()
def MethodA(self):
print 'A method'
>>> class child1(Parent):
def MethodA(self):
print 'child1 method'
>>> x = child1()
child1 method
>>> x.MethodA()
child1 method

Categories

Resources