Python's Class Inheritance - python

# Defining a Base class to be shared among many other classes later:
class Base(dict):
"""Base is the base class from which all the class will derrive.
"""
name = 'name'
def __init__( self):
"""Initialise Base Class
"""
dict.__init__(self)
self[Base.name] = ""
# I create an instance of the Base class:
my_base_instance = Base()
# Since a Base class inherited from a build in 'dict' the instance of the class is a dictionary. I can print it out with:
print my_base_instance Results to: {'name': ''}
# Now I am defining a Project class which should inherit from an instance of Base class:
class Project(object):
def __init__(self):
print "OK"
self['id'] = ''
# Trying to create an instance of Project class and getting the error:
project_class = Project(base_class)
TypeError: __init__() takes exactly 1 argument (2 given)

there are two mistakes in your code:
1) Class inheritance
class Project(Base): # you should inherit from Base here...
def __init__(self):
print "OK"
self['id'] = ''
2) Instance definition (your __init__ does not requires any explicit parameter, and for sure not the ancestor class)
project_class = Project() # ...and not here since this is an instance, not a Class

When you're instantiating a class, you don't need to pass in base_class. That's done at definition. __init__ takes exactly 1 argument, which is self, and automatic. You just need to call
project_class = Project()

For Project to inherit from Base, you should not subclass it from object but from Base i.e class Project(Base). You get TypeError: init() takes exactly 1 argument (2 given) error when you instantiate Project class because the constructor takes only 1 parameter(self) and you pass base_class too. 'self' is passed implicitly by python.

Related

How to use self in an abstract class implementation in Python?

I'm working on a project using abstract classes in Python (specifically, the abc module).
I have a few implementations of this abstract class, which have their own constructors and need to use self.
This is what my code looks like, but simplified:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = [] # not meant to be passed in, that's why it isn't an argument in __init__
#classmethod
def display(cls):
print(cls.get_contents())
#abstractmethod
def get_contents():
pass
class ImplementationOne(Base):
def __init__(self, url):
self.url = url
def get_contents(self):
return "The url was: " + url
class ImplementationTwo(Base):
def get_contents():
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
When I run this, however, I get the error TypeError: get_contents() missing 1 required positional argument: 'self'.
I figured that this is because get_contents() in ImplementationOne takes self, but it's not specified in the abstract method.
So, if I changed:
#abstractmethod
def get_contents():
pass
to
#abstractmethod
def get_contents(self):
pass
But I get the same error.
I've tried many combinations, including putting self as an argument to every occurrence or get_contents, and passing in cls to get_contents in the abstract class - but no luck.
So, pretty much, how can I use the self keyword (aka access attributes) in only some implementations of an abstract method, that's called within a class method in the abstract class itself.
Also, on a side note, how can I access self.sublinks from within all implementations of BaseClass, while having its values different in each instance of an implementation?
There are a few things wrong here. One is that the #classmethod decorator should only be used when you need it to be called on a class.
Example:
class ImplementationOne:
#classmethod
def display(cls):
print(f'The class name is {cls.__name__}.')
ImplementationOne.display()
There is nothing special about the name self. It's just what is used by everyone to refer to the instance. In python the instance is implicitly handed to the first argument of the class unless you have a #classmethod decorator. In that case the class is handed as the first argument.
That is why you are getting the TypeError. Since you are calling the method on the instance test_one.display() you are essentially calling it as an instance method. Since you need to access the instance method get_contents from within it that is what you want. As a classmethod you wouldn't have access to get_contents.
That means you need both the ABC and ImplementationOne to have those methods implemented as instance methods.
Since it is now an instance method on the ABC it also should be an instance method in ImplementationTwo.
Your other question was how to get self.sublinks as an attribute in both subclasses.
Since your are overriding __init__ in ImplementationOne you need to call the parent class's __init__ as well. You can do this by using super() to call the Super or Base class's methods.
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
Full working code:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = []
def display(self):
print(self.get_contents())
#abstractmethod
def get_contents(self):
pass
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
def get_contents(self):
return "The url was: " + self.url
class ImplementationTwo(BaseClass):
def get_contents(self):
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
test_two.display()
print(test_one.sublinks)

how can I get instance list of specific class in python [duplicate]

I wrote a Python module, with several classes that inherit from a single class called MasterBlock.
I want to import this module in a script, create several instances of these classes, and then get a list of all the existing instances of all the childrens of this MasterBlock class. I found some solutions with vars()['Blocks.MasterBlock'].__subclasses__() but as the instances I have are child of child of MasterBlock, it doesn't work.
Here is some example code:
Module:
Class MasterBlock:
def main(self):
pass
Class RandomA(MasterBlock):
def __init__(self):
pass
# inherit the main function
Class AnotherRandom(MasterBlock):
def __init__(self):
pass
# inherit the main function
Script:
import module
a=module.RandomA()
b=module.AnotherRandom()
c=module.AnotherRandom()
# here I need to get list_of_instances=[a,b,c]
Th ultimate goal is to be able to do:
for instance in list_of_instances:
instance.main()
If you add a __new__() method as shown below to your base class which keeps track of all instances created in a class variable, you could make the process more-or-less automatic and not have to remember to call something in the __init__() of each subclass.
class MasterBlock(object):
instances = []
def __new__(cls, *args, **kwargs):
instance = super(MasterBlock, cls).__new__(cls, *args, **kwargs)
instance.instances.append(instance)
return instance
def main(self):
print('in main of', self.__class__.__name__) # for testing purposes
class RandomA(MasterBlock):
def __init__(self):
pass
# inherit the main function
class AnotherRandom(RandomA): # works for sub-subclasses, too
def __init__(self):
pass
# inherit the main function
a=RandomA()
b=AnotherRandom()
c=AnotherRandom()
for instance in MasterBlock.instances:
instance.main()
Output:
in main of RandomA
in main of AnotherRandom
in main of AnotherRandom
What about adding a class variable, that contains all the instances of MasterBlock? You can record them with:
Class MasterBlock(object):
all_instances = [] # All instances of MasterBlock
def __init__(self,…):
…
self.all_instances.append(self) # Not added if an exception is raised before
You get all the instances of MasterBlock with MasterBlock.all_instances (or instance.all_instances).
This works if all base classes call the __init__ of the master class (either implicitly through inheritance or explicitly through the usual super() call).
Here's a way of doing that using a class variable:
class MasterBlock(object):
instances = []
def __init__(self):
self.instances.append(self)
def main(self):
print "I am", self
class RandomA(MasterBlock):
def __init__(self):
super(RandomA, self).__init__()
# other init...
class AnotherRandom(MasterBlock):
def __init__(self):
super(AnotherRandom, self).__init__()
# other init...
a = RandomA()
b = AnotherRandom()
c = AnotherRandom()
# here I need to get list_of_instances=[a,b,c]
for instance in MasterBlock.instances:
instance.main()
(you can make it simpler if you don't need __init__ in the subclasses)
output:
I am <__main__.RandomA object at 0x7faa46683610>
I am <__main__.AnotherRandom object at 0x7faa46683650>
I am <__main__.AnotherRandom object at 0x7faa46683690>

Python: add a class to another classes bases

im trying to add a class to another classes bases:
class A(object):
def __init__(self, name):
self.name = name
class AMixin(object):
def mixinExample(self):
return ("in AMixin.mixinExample" + self.name)
def MixIn(TargetClass, MixInClass):
if MixInClass not in TargetClass.__bases__:
TargetClass.__bases__ += (MixInClass,)
if __name__ == "__main__":
a_instance = A("Q7")
MixIn(A,AMixin)
print(a_instance.mixinExample())
and i get this error:
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, AMixin
I got this error because both of the classes (A and AMixin) inherent from 'object'?
You're trying to set A's bases to (object, AMixin). This ordering means that object methods should override AMixin methods.
However, AMixin inherits from object, and that means that AMixin methods should override object methods.
It is not possible for both of those requirements to be satisfied, hence the error.

Extend Python class's init method

I have a BaseClass and an AbstractClass that inherits from the BaseClass. This is the structure I have in place
class BaseClass(object):
def __init__(self, initialize=True):
self.name = 'base_class'
self.start = 0
if initialize:
self.start = 100
class AbstractClass(BaseClass):
def __init__(self):
self.name = 'asbtract_class'
super(BaseClass, self).__init__()
I want to pass the abstract class an initialize parameter that gets transferred to the base class and if True sets the object's start value to 100.
I tried using the super(BaseClass, self).__init__() but the abstract class gets no start attribute. I get an error when I try to access it.
How can I pass a value the initialize argument to the AbstractClass and use the BaseClass's __init__ method to set the start attribute on the AbstractClass.
The code I used
best = BaseClass()
abs = AbstractClass()
abs.start # AttributeError: 'AbstractClass' object has no attribute 'start'
To invoke the constructor of the super class you should use the class name of the sub class and not the super class, i.e.:
class AbstractClass(BaseClass):
def __init__(self):
super(AbstractClass, self).__init__()
self.name = 'abstract_class'
Note also that I changed the order of invoking the constructor of the super class and setting the name attribute. If you set it before calling the super, the attribute would be overridden by the constructor of the super class, which is most likely not what you intended
And as #Sraw pointed out, for python 3 the notation of calling the super no longer requires the referencing of the class name and can be simplified to
class AbstractClass(BaseClass):
def __init__(self):
super().__init__()

How do derived class constructors work in python?

I have the following base class:
class NeuralNetworkBase:
def __init__(self, numberOfInputs, numberOfHiddenNeurons, numberOfOutputs):
self.inputLayer = numpy.zeros(shape = (numberOfInputs))
self.hiddenLayer = numpy.zeros(shape = (numberOfHiddenNeurons))
self.outputLayer = numpy.zeros(shape = (numberOfOutputs))
self.hiddenLayerWeights = numpy.zeros(shape = (numberOfInputs, numberOfHiddenNeurons))
self.outputLayerWeights = numpy.zeros(shape = (numberOfHiddenNeurons, numberOfOutputs))
now, I have a derived class with the following code:
class NeuralNetworkBackPropagation(NeuralNetworkBase):
def __init__(self, numberOfInputs, numberOfHiddenNeurons, numberOfOutputs):
self.outputLayerDeltas = numpy.zeros(shape = (numberOfOutputs))
self.hiddenLayerDeltas = numpy.zeros(shape = (numberOfHiddenNeurons))
But when I instantiate NeuralNetworkBackPropagation I'd like that both constructors get called.This is, I don't want to override the base class' constructor. Does python call by default the base class constructor's when running the derived class' one? Do I have to implicitly do it inside the derived class constructor?
Does python call by default the base
class constructor's when running the
derived class' one? Do I have to
implicitly do it inside the derived
class constructor?
No and yes.
This is consistent with the way Python handles other overridden methods - you have to explicitly call any method from the base class that's been overridden if you want that functionality to be used in the inherited class.
Your constructor should look something like this:
def __init__(self, numberOfInputs, numberOfHiddenNeurons, numberOfOutputs):
NeuralNetworkBase.__init__(self, numberOfInputers, numberOfHiddenNeurons, numberOfOutputs)
self.outputLayerDeltas = numpy.zeros(shape = (numberOfOutputs))
self.hiddenLayerDeltas = numpy.zeros(shape = (numberOfHiddenNeurons))
Alternatively, you could use Python's super function to achieve the same thing, but you need to be careful when using it.
You will have to put this in the __init__() method of NeuralNetworkBackPropagation, that is to call the __init__() method of the parent class (NeuralNetworkBase):
NeuralNetworkBase.__init__(self, numberOfInputs, numberOfHiddenNeurons, numberOfOutputs)
The constructor of the parent class is always called automatically unless you overwrite it in the child class. If you overwrite it in the child class and want to call the parent's class constructor as well, then you'll have to do it as I showed above.

Categories