python 2.7 - how to call parent class constructor - python

I have base class like below
class FileUtil:
def __init__(self):
self.outFileDir = os.path.join(settings.MEDIA_ROOT,'processed')
if not os.path.exists(outFileDir):
os.makedirs(outFileDir)
## other methods of the class
and I am extending this class as below:
class Myfile(FileUtil):
def __init__(self, extension):
super(Myfile, self).__init__()
self.extension = 'text'
## other methods of class
But i am getting below error?
super(Myfile, self).__init__()
TypeError: super() takes at least 1 argument (0 given)
I gone through many documents and found that there are different sytex of calling super() in 2.x and 3.x. I tried both ways but getting error.

You have 2 options
old style class, you should call the super constructor directly.
class FileUtil():
def __init__(self):
pass
class Myfile(FileUtil):
def __init__(self, extension):
FileUtil.__init__(self)
new style class, inherit from object in your base class and your current call to super will be processed correctly.
class FileUtil(object):
def __init__(self):
pass
class Myfile(FileUtil):
def __init__(self, extension):
super(Myfile, self).__init__()

You may need to create the FileUtil class using the super() function as well:
class FileUtil(object):
def __init__(self):
super(FileUtil, self).__init__()
...

Related

python using super(), can't access variable from second parent class

This is probably very simple question. In a child class, which is inherited from two parent classes, I can't access variable from second parent class using super(). Here is my code:
class Core:
def __init__(self):
self.a_from_Core = 7
class Extra:
def __init__(self):
self.b_from_Extra = 90
class Trash(Core, Extra):
def __init__(self):
super().__init__()
print(self.a_from_Core) # working
print(self.b_from_Extra) # does not work
trashcan = Trash()
And here is error:
AttributeError: 'Trash' object has no attribute 'b_from_Extra'
What am I doing wrong?
Python uses "cooperative" multiple inheritance (https://rhettinger.wordpress.com/2011/05/26/super-considered-super/)
which kinda means all classes involved in the inheritance need to agree to play.
For single inheritance, it just works -- which is what lulled you into thinking it would work for multiple.
You need to add calls to super().__init__() in all classes, for example
class Core:
def __init__(self):
self.a_from_Core = 7
super().__init__() # added
class Extra:
def __init__(self):
self.b_from_Extra = 90
super().__init__() # added
class Trash(Core, Extra):
def __init__(self):
super().__init__()
print(self.a_from_Core)
print(self.b_from_Extra) # works!
trashcan = Trash()
You are inheriting from two classes, according to MRO, your first father is Core and your second father is Extra.
So when you call super, the __init__ in Core is called and the __init__ in the Extra is not called, so you don't have b_from_Extra.
As in MRO of Trash you have something like: [..., Core, Extra], if you call super in Core, the method in Extra would be called.
So you can do the following :
class Core:
def __init__(self):
self.a_from_Core = 7
super().__init__()
...
You can read about MRO.

How to pass variables from parent class to child class?

As I know, the typical child class of python might should be:
class Parent:
"""CODE HERE"""
class Child(Parent):
"""CODE HERE"""
But this doesn't fit my situation. I would like that, when the variable of parent class changes, the child class changes together. So I have to use:
class Session:
def __init__(self):
self.token = 'FoObArFooBar'
self.api_url = f'https://example.com/post/{self.token}'
class Post:
def __init__(self):
pass
def post(self):
requests.post(super.api_url)
So that when I change Session.api_url, the child class Post also changes. But I got this error:
----> 1 Session.Post.post()
TypeError: post() missing 1 required positional argument: 'self'
So how to pass variables in this situation? Thanks.

Pass in wrong class still works?

Usually super works like the following in Python:
class SubClass(MyParentClass):
def __init__(self):
super(**SubClass**, self).__init__()
But recently I found something like the following also works? No crash, behaviors as expected:
class SubClass(MyParentClass):
def __init__(self):
super(**MyParentClass**, self).__init__()
How come? What does the second case mean?
super(MyParentClass, self).__init__() Will call grandparent class (If it has one)
class BaseClass:
def __init__(self):
print("BaseClass")
class MyParentClass(BaseClass):
def __init__(self):
print("MyParentClass")
class SubClass(MyParentClass):
def __init__(self):
super(SubClass, self).__init__()
class SubClassTwo(MyParentClass):
def __init__(self):
super(MyParentClass, self).__init__()
SubClass() # output: MyParentClass
SubClassTwo() # output: BaseClass
Actually, the behaviour it's not the same.
From the documentation of super() (docs here):
Return a proxy object that delegates method calls to a parent or
sibling class of type.
So if you have:
class MyParentClass:
def __init__(self):
print('MyParentClass.__init__ called!')
class SubClass(MyParentClass):
def __init__(self):
super(MyParentClass, self).__init__()
The call:
super(MyParentClass, self).__init__()
has no effect, because MyParentClass has no parents but object.
If you call:
super(SubClass, self).__init__()
It will print:
MyParentClass.__init__ called!
Because SubClass has one parent, MyParentClass.
The documentation for super says (in part):
super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or
sibling class of type. This is useful for accessing inherited methods
that have been overridden in a class. The search order is same as that
used by getattr() except that the type itself is skipped.
So super(MyParentClass, self) resolves to a proxy object that will pass method calls through to the parents and siblings of MyParentClass. It shouldn't be surprising that this works. If your parent class is
class MyParentClass:
def __init__(self, **kwargs):
...
super(MyParentClass, self).__init__(kwargs)
Then when you make a SubClass object, the self in the MyParentClass super call is a SubClass instance.

How can I add to the initial definition of a python class inheriting from another class?

I'm trying to define self.data inside a class inheriting from a class
class Object():
def __init__(self):
self.data="1234"
class New_Object(Object):
# Code changing self.data here
But I ran into an issue.
class Object():
def __init__(self):
self.data="1234"
So I have the beginning class here, which is imported from elsewhere, and let's say that the class is a universal one so I can't modify the original at all.
In the original, the instance is referred to as "self" inside the class, and it is defined as self inside the definition __init__.
class New_Object(Object):
# Code changing self.data here
So if I wanted to inherit from the class Object, but define self.data inside New_Object, I thought I would have to define __init__ in New_Object, but this overrides the __init__ from New_Object
Is there any way I could do this without copypasting the __init__ from Object?
You use super to call the original implementation.
class New_Object(Object):
def __init__(self):
super(NewObject, self).__init__()
self.info = 'whatever'
That's what super is for:
class NewObject(Object):
def __init__(self):
super(NewObject, self).__init__()
# self.data exists now, and you can modify it if necessary
You can use super().__init__() to call Object.__init__() from New_Object.__init__().
What you would do:
class Object:
def __init__(self):
print("Object init")
self.data = "1234"
class New_Object(Object):
def __init__(self):
print("calling super")
super().__init__()
print("data is now", self.data)
self.data = self.data.split("3")
o = New_Object()
# calling super
# Object init
# data is now 1234
Note that you do not have to give any arguments to super(), as long as you are using Python 3.
The answer is that you call the superclass's __init__ explicitly during the subclass's __init__. This can be done either of two ways:
Object.__init__(self) # requires you to name the superclass explicitly
or
super(NewObject, self).__init__() # requires you to name the subclass explicitly
The latter also requires you to ensure that you're using "new-style" classes: in Python 3 that's always the case, but in Python 2 you must be sure to inherit from the builtin object class. In Python 3 it can actually be expressed even more simply:
super().__init__()
Personally, in most of my code the "disadvantage" of having to name the superclass explicitly is no disadvantage at all, and Object.__init__() lends transparency since it makes it absolutely clear what is being called. This is because most of my code is single-inheritance only. The super route comes into its own when you have multiple inheritance. See What does 'super' do in Python?
Python 2 example:
class Object(object):
def __init__(self):
self.data = "1234"
class NewObject:
def __init__(self):
# subclass-specific stuff
super(NewObject, self).__init__()
# more subclass-specific stuff

Python :: Attribute in superclass not available in inheriting subclass

I'm wondering why the below fails; basically that an inheriting subclass (SubClass) doesn't appear to have access to an attribute in the superclass (SuperClass) that it inherits from.
By the way, all three files below are in the same directory and, for completeness, I'm using Python3.
Any ideas? I think it's something stunningly simple. Thank you!
The super class (SuperClass in ./super_class.py) ...
class SuperClass(object):
def __init__(self):
self.varSuper = 'varSuper_value'
The inheriting sub class (SubClass in ./sub_class.py) ...
from super_class import SuperClass
class SubClass(SuperClass):
def __init__(self):
super(SuperClass, self).__init__()
self.varSub = 'varSub_value'
The driver/tester script (./driver.py) ...
#! /usr/bin/env python3
from sub_class import SubClass
print(SubClass().varSub) # Works: "varSub_value"
print(SubClass().varSuper) # Excepts: I expected "varSuper_value"
The exception ...
user#linux$ ./driver.py
varSub_value <--- GOOD
Traceback (most recent call last):
File "./driver.py", line 6, in <module>
print(SubClass().varSuper) <--- NO GOOD
AttributeError: 'SubClass' object has no attribute 'varSuper'
You are using the super() function wrong. You should be using:
super(SubClass, self).__init__()
Or in python3
super().__init__()
The way you have it written you are starting the MRO just after the parent class, not just after your own class..
In the inheriting sub class (SubClass in ./sub_class.py), change this:
from super_class import SuperClass
class SubClass(SuperClass):
def __init__(self):
super(SuperClass, self).__init__() # <---- INCORRECT. CHANGE THIS.
self.varSub = 'varSub_value'
To this:
from super_class import SuperClass
class SubClass(SuperClass):
def __init__(self):
super(SubClass, self).__init__() # <---- TO THIS in python-2 (also still valid in Python-3)
super().__init__() # <---- OR THIS for python-3 (New style in python-3)
self.varSub = 'varSub_value'
Btw, the python-3 new incantation avoids the possible bug of typing the wrong class.

Categories

Resources