How to subclass an Abstract Base Class? - python

Let's say I have an ABC:
class Template_ABC(metaclass=abc.ABCMeta):
def __init__(self, data=None, model=None):
self._data = data
self._model = model
#abc.abstractmethod
def do_stuff(self):
pass
#abc.abstractmethod
def do_more_stuff(self):
pass
I normally have a class of ABC, for example:
class Example_of_ABC(Template_ABC):
def do_stuff(self):
# Do stuff here
def do_more_stuff(self):
pass
Now, I want to subclass Example-of_ABC class. The only way I can do is as as follows:
class Subclass_of_Example_of_ABC(Example_of_ABC):
def __init__(self, data=None, model=None):
super().__init__(data, model)
def do_more_stuff(self):
# Do more stuff here
The issue with this way, is that I have to update my def _init__() for every subclass of the ABC. Is there anyway for the subclass to inherit all the inits from the ABC?

Related

How to inherit all class attributes, but one? Python

How to inherit all class 'A' attributes and methods, but 'b()'?
class A:
def __init__(self):
# attributes
pass
#classmethod
def b(cls):
# logic
pass
class B(A):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def b(self):
# nothing
pass
do not use this old method( if there is another way to do it ):
class B(A):
def __init__(self, attributes):
super().__init__(self, attributes)
You can reimplement b() to raise an error:
class A:
def __init__(self):
# attributes
pass
#classmethod
def b(cls):
# logic
pass
class B(A):
def __init__(self, **kwargs):
super().__init__(**kwargs)
#classmethod
def b(cls):
raise TypeError("method b is not supported in class B")
Also, if b() is a classmethod, you should probably override it as a classmethod.
Put that method in a separate class and don't inherit it.
class A:
def __init__(self):
# attributes
pass
class A1:
#classmethod
def b(cls):
# logic
pass
class B(A):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Use multiple inheritance when you want that method.
class C(A,A1):
pass

How to avoid duplicate code if two classes extending different classes

I have two classes which extend two different base classes. Those classes setup custom environment.
The are three methods common in both the classes: prepare(), setup() and teardown().
Each method overrides base class method. (Also they have super() calls.) Also ExtendedBase extends Base.
First class:
ClassA(Base):
def __init__(self, args):
super().__init__(args)
self._private = OtherClass()
def prepare(self, args):
super().prepare(args)
self._private.prepare()
def setup(self, args):
super().setup(args)
self._private.setup(self._smth, args)
def teardown(self):
self._private.teardown()
super().teardown()
Second class:
ClassB(ExtendedBase):
def __init__(self, args):
super().__init__(args)
self._private = OtherClass()
def prepare(self, args):
super().prepare(args)
self._private.prepare()
def setup(self, args):
super().setup(args)
self._private.setup(self._smth, args)
def teardown(self):
self._private.teardown()
super().teardown()
Is this a way to avoid duplicate methods?
I thought about multiple inheritance with the Environment class which will contain duplicated methods, but am puzzled about how to implement this and if it is a good idea at all.
Edited: Unfortunately I couldn't do anything with classes hierarchy. ClassA and ClassB should inherit corresponding classes and override or use the parent's method.
This look a lot like a typical case to use class mixin:
class BuildMixin:
def __init_(self, args):
super().__init__(args)
self._private = OtherClass()
def prepare(self, args):
super().prepare(args)
self._private.prepare()
def setup(self, args):
super().setup(args)
self._private.setup(self._smth, args)
def teardown(self):
self._private.teardown()
super().teardown()
class ClassA(BuildMixin, Base):
pass
class ClassB(BuildMixin, ExtendedBase):
pass
For illustration purposes here are a bunch of dummy classes that follow your example and use mixin. From your question it is not clear what OtherClass should be, but it seems it also has the prepare, teardown and setup methods:
class OtherClass:
def prepare(self,arg):
print('OC perparing')
def teardown(self):
print('OC tearing down')
def setup(self, smth, args):
print('OC setting up')
class Base:
def __init__(self, args):
print('Base init')
self._smth=args
def prepare(self,arg):
print('Base perparing')
def teardown(self,):
print('base tearing down')
def setup(self,args):
print('base setting up')
class ExtendedBase:
def __init__(self, args):
print('ExtBase init')
self._smth=args
def prepare(self, arg):
print('ExtBase perparing')
def teardown(self):
print('ExtBase tearing down')
def setup(self, arg):
print('ExtBase setting up')
class BuildMixin:
def __init__(self, arg):
super().__init__(arg)
self._private = OtherClass()
def prepare(self, args):
super().prepare(args)
self._private.prepare(args)
def setup(self, args):
super().setup(args)
self._private.setup(self._smth, args)
def teardown(self):
self._private.teardown()
super().teardown()
class ClassA(BuildMixin, Base):
pass
class ClassB(BuildMixin, ExtendedBase):
pass
a = ClassA(1)
# prints:
# Base init
b = ClassB(1)
# prints:
# ExtBase init
a.prepare(1)
# prints:
# Base perparing
# OC perparing
b.prepare(1)
# prints:
# ExtBase perparing
# OC perparing
# and so on...

How to inherit from pre-existing class instance in Python?

I have a class Parent:
class Parent:
def __init__(self, foo):
self.foo = foo
I then have another class Child which extends Parent. But I want Child to take a pre-existing instance of parent and use this as the parent to inherit from (instead of creating a new instance of Parent with the same constructor parameters).
class Child(Parent):
def __init__(self, parent_instance):
""" Do something with parent_instance to set this as the parent instance """
def get_foo(self):
return self.foo
Then I would ideally be able to do:
p = Parent("bar")
c = Child(p)
print(c.get_foo()) # prints "bar"
You could copy the content of the parents's __dict__ to the child's. You can use vars() builtin function to do so, and the dictionary's update() method.
class Child(Parent):
def __init__(self, parent_instance):
vars(self).update(vars(parent_instance))
def get_foo(self):
return self.foo
p = Parent("bar")
c = Child(p)
print(c.get_foo())
# prints "bar"
You can use your own constructor - provide a classmethod that takes an instance of a parent.
class Parent:
def __init__(self, foo):
self.foo = foo
class Child(Parent):
def get_foo(self):
return self.foo
#classmethod
def from_parent(cls, parent_instance):
return cls(parent_instance.foo)
p = Parent('bar')
c = Child.from_parent(p)
c.get_foo()
I'm not sure inheritance is the right solution here as it breaks the LSP in the __init__ method.
Maybe parents and children just share a common interface.
I'd prefer something like (python3.8):
from typing import Protocol
class FoeAware(Protocol):
#property
def foe(self):
...
class Parent:
def __init__(self, foe):
self._foe = foe
#property
def foe(self):
return self._foe
class Child:
def __init__(self, parent: FoeAware):
self.parent = parent
#property
def foe(self):
return self.parent.foe
p = Parent("bar")
c = Child(p)
c.foe # bar
The key point is that it takes advantage of polymorphism with a common interface FoeAware, which is preferable to an inheritance tree.
Using getattr() to fetch the attribute from the parent instance
class Parent:
def __init__(self, foo):
self.foo = foo
class Child(Parent):
def __init__(self, parent_instance):
self.parent_instance = parent_instance
def get_foo(self):
return self.foo
def __getattr__(self, attr):
return getattr(self.parent_instance, attr)
par = Parent("bar")
ch = Child(par)
print(ch.get_foo())
#prints bar

Is is possible to call the child classes and the parent class from another python script dynamically

class Animal(self):
def putData(self, dict)
# do something
# abc.abstractmethod
def getSum(self, *args, **kwargs):
pass
class Dog(Animal):
def display(self):
# do something
def getSum(self,count):
# do something
class Cat(Animal):
def calculate(self):
# do something
def getSum(self,*dict):
# do something
All these class files are in folder /username/pacagename/ and the python script from which i have to call these 4 classes is in /username/packagename/bin

Is it ok to have a property decorated method to return a class in Python?

Let's say I have the following code:
class MyClass(object):
def __init__(self, param):
self.param = param
#property
def super_param(self):
return Param(self, self.param)
class Param(object):
def __init__(self, parent, param):
self.param = param
self.parent = parent
#property
def get_parent(self):
return self.parent
My question is, is it considered bad practice to use the #property decorator in this way? Are there any pros or cons?
Why not just
class MyClass(object):
def __init__(self, param):
self.param = Param(self, param)
I don't think there's anything particularly wrong with returning a class from a property; a better question is, what are you trying to accomplish by doing so?
Edit: if you don't want it changed, make it a private property:
class MyClass(object):
def __init__(self, param):
self._param = param # naming convention, 'don't muck with it'
# OR
self.__param = param # name mangled
#property
def param(self):
return self._param

Categories

Resources