Subclassing a Python class to inherit attributes of super class - python

I'm trying to inherit attributes from a super class but they are not being initialized correctly:
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
super(Thing, self).__init__()
print self.attribute1
This throws an error since attribute1 is not an attribute of OtherThing, even though Thing.attribute1 exists. I thought this was the correct way to inherit and extend a super class. Am I doing something wrong? I don't want to create an instance of Thing and use its attributes, I need it to inherit this for simplicity.

You have to give, as argument, the class name (where it is being called) to super():
super(OtherThing, self).__init__()
According to Python docs:
... super can be used to refer to parent classes without naming them
explicitly, thus making the code more maintainable.
so you are not supposed to give the parent class.
See this example from Python docs too:
class C(B):
def method(self, arg):
super(C, self).method(arg)

Python3 makes this easy:
#!/usr/local/cpython-3.3/bin/python
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
#super(Thing, self).__init__()
super().__init__()
print(self.attribute1)
def main():
otherthing = OtherThing()
main()

Related

suppress calling __init__() of parent class

I just noticed some unintended behaviour then tested it in an interpretor (Python 3.5.3):
>>> class SomeClass:
... def __init__(self):
... print("nothing important")
...
>>> a = SomeClass()
nothing important
>>> class SomeOtherClass(SomeClass):
... pass
...
>>> b = SomeOtherClass()
nothing important
>>>
I thought you needed to directly call the parents __init__(). What is the simplest way to write or instantiate the child class such that it does not run the __init__() from the parent class?
You can by defining an __init__ method in the child class:
class SomeOtherClass(SomeClass):
def __init__(self):
pass
I want some methods from the parent, just not that the init runs
Then your design is wrong. If you only care about code reuse but not proper subtyping (as defined by Liskov), proper designs are either composition/delegation or (probably the best in your case) multiple inheritance with mixin classes:
class CommonMixin():
def method1(self):
pass
def method2(self):
pass
class SomeClass(CommonMixin, SomeBaseClass):
def __init__(self):
print("nothing important")
class SomeOtherClass(CommonMixin, SomeOtherBaseClass):
pass

How to retrieve the names of children classes in the inherited one?

I have a base class which I inherit from when creating other classes.
One of the things I would like to do is, at __init__() time, to log the parent class the object is instantied from. Today I do it the explicit way:
class Main:
def __init__(self, src):
print(f"hello from {src}")
class One(Main):
def __init__(self):
super().__init__("one")
class Two(Main):
def __init__(self):
super().__init__("two")
One()
Two()
This outputs
hello from one
hello from two
Is there a way for Main to know which class ultimately instantiated the object?
I am thinking of something along the lines of (this is just a wildly hand-waving example, to show what that I would like to call bare a bare __init__ instead of also passing a descriptive parameter as in the code above)
class Main:
def __init__(self, src):
wherefrom = something_which_holds_the_class_hierarchy[1].__name__ # index 1 = one class above this one
print(f"hello from {wherefrom}")
class One(Main):
def __init__(self):
super().__init__()
class Two(Main):
def __init__(self):
super().__init__()
One()
Two()
No need for messing with MROs for this, just look at type(self):
class Main:
def __init__(self):
print(f"Hello from {type(self).__name__}!")
class Sub(Main):
pass
class SubSub(Sub):
pass
Main()
Sub()
SubSub()
results in:
Hello from Main!
Hello from Sub!
Hello from SubSub!
self.__class__ is equivalent to type(self), you can use either.
print(f"hello from {self.__class__}")
use inspect.getmro function
import inspect
inspect.getmro(Two)

Refer to a class outside its method?

I need to deliver something like this in my program
class the_class_name(Parent):
the_attribute = self.parent_class_method()
#the parent class method will return a value
#but I cannot use self here since there's no self
How can I carry this out? Is there any other alternative that can do the job for me?
I have tried using __init__ like this:
def __init__(self):
Parent.__init__(self)
self.attribute = self.the_method()
But then I have problem creating the object, it won't receive any parameters that the Parent class normally receives anymore
Sounds like you are looking for __init__:
class TheClassName(Parent):
def __init__(self):
# Set attribute to the result of the parent method
self.attribute = super(TheClassName, self).the_method()
EDIT
If your parent class has parameters in it's own __init__ function, include them in the child class:
class Parent(object):
def __init__(self, foo, bar):
...
#classmethod
def the_method(cls):
...
class TheClassName(Parent):
def __init__(self, foo, bar):
super(TheClassName, self).__init__(foo, bar)
self.attribute = super(TheClassName, self).the_method()
I don't quite understand why you don't just call the parent method on your child object when you need the value though.
There is no self at that point of the creation of the subclass, nor is there an instance of the Parent class. That means the only Parent class methods you could call would have to be either static or class methods.
To demonstrate:
class Parent(object):
#staticmethod
def static_method():
return 42
#classmethod
def class_method(cls):
return 43
class TheClassName(Parent):
the_attribute = Parent.static_method()
another_attribute = Parent.class_method()
print(TheClassName.the_attribute) # -> 42
print(TheClassName.another_attribute) # -> 43
You must use class methods, declared with the #classmethod decorator, or a #staticmethod. The #classmethod decorator is preferable so that inheritance is handled correctly, i.e. the method is invoked on the derived class (a bit of a technicality, if you are still learning this).
class Alpha(object):
#classmethod
def method1(cls):
return 'method1 has been called on {}'.format(cls)
class Beta(Alpha):
def __init__(self):
self.myattr = Beta.method1()
print(Beta().myattr)
method1 has been called on class <'__main__.Beta'>
Use
super(ClassName, self).methodname(arg)
inside a method
def child_method(self, arg):
super(ClassName, self).methodname(arg)
You cannot use self outside a method.

Inheritance in python 2.7

I am attempting to build a framework for parsing a very specific text structure.
The structure that I am processing is rich and has a known schema, similar to xml.
I am attempting to build an framework to do the parsing. The text has various sections and I anticipate that more sections code be added in the future. To Compensate, I am attempting to build a series of derived classed that can be swapped in or out as needed.
I thought everything was going as planned, until I started coding up the first derived class.
The base class has some functionality inside of __init__ that I was expecting that I would get for free in all of the concrete derived classes. That however, doesn't seem to be the case at all.
Here is a simple example to illustrate my problem:
I would expect the output to be:
['memberA', 'memberB', 'memberC'],
['DerivedA', 'DerivedB', 'DerivedC']
class base(object):
def __init__(self):
members = [attr for attr in dir(self) if not callable(attr) and not attr.startswith("__")]
print members
class test(base):
def __init__(self):
self.memberA = None
self.memberB = None
self.memberC = None
class test2(test):
def __init__(self):
self.DerivedA = None
self.DerivedB = None
self.DerivedC = None
t = test()
t2 = test2()
Can someone please explain to my, why the print functionality is not working as I expect it?
EDIT:
in light of the answer below: I now have this question:
What if base.__init(self) instead looked like:
class base(object):
def __init__(self, text):
would I have to define the derived class as:
class test(base):
def __init__(self, text):
base.__init__(self, text)
I was hoping to at least get the parameter object referance for free
In Python, you must call the base class's __init__ explicitly inside test.__init__:
class test(base):
def __init__(self):
base.__init__(self)
Or, if you wish to support multiple inheritance, use super:
class test(base):
def __init__(self):
super(test, self).__init__()
If the base.__init__ looks like
class base(object):
def __init__(self, text):
then test.__init__ should indeed look like
class test(base):
def __init__(self, text):
base.__init__(self, text)
See Guido van Rossum's blog for why self is explicit in Python.
PS. PEP8 recommends using CapWords for class names.
you are overwriting init in test2
following code will complete overwrite init in test. so there is no longer a print int the init function.
def __init__(self):
self.DerivedA = None
self.DerivedB = None
self.DerivedC = None

Can't access parent member variable in Python

I'm trying to access a parent member variable from an extended class. But running the following code...
class Mother(object):
def __init__(self):
self._haircolor = "Brown"
class Child(Mother):
def __init__(self):
Mother.__init__(self)
def print_haircolor(self):
print Mother._haircolor
c = Child()
c.print_haircolor()
Gets me this error:
AttributeError: type object 'Mother' has no attribute '_haircolor'
What am I doing wrong?
You're mixing up class and instance attributes.
print self._haircolor
You want the instance attribute, not the class attribute, so you should use self._haircolor.
Also, you really should use super in the __init__ in case you decide to change your inheritance to Father or something.
class Child(Mother):
def __init__(self):
super(Child, self).__init__()
def print_haircolor(self):
print self._haircolor

Categories