In python I can do this:
import mechanize
class MC (object):
def __init__(self):
self.Browser = mechanize.Browser()
self.Browser.set_handle_equiv(True)
def open (self,url):
self.url = url
self.Browser.open(self.url)
My question is: how can I __init__ a parent class method in a subclass (that is something like this):
class MC (mechanize.Browser):
def __init__(self):
self.Browser.set_handle_equiv(True)
Help much appriciated!
Just call the method directly, methods on base classes are available on your instance during initialisation:
class MC(mechanize.Browser):
def __init__(self):
self.set_handle_equiv(True)
You probably want to call the base-class __init__ method as well though:
class MC(mechanize.Browser):
def __init__(self):
mechanize.Browser.__init__(self)
self.set_handle_equiv(True)
We need to call the __init__ directly because Browser is an old-style python class; in a new-style python class we'd use super(MC, self).__init__() instead, where the super() function provides a proxy object that searches the base class hierarchy to find the next matching method you want to call.
Related
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.
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
I'm trying to subclass a class from another python script.
I've done the following when subclassing from within the same file, and it works.
widge.py
class widget(object):
def __init__(self,bob):
#do something
class evenWidgetier(widget):
def __init__(self, bob):
widget.__init__(self,bob)
#do something
But once I add in inheritance from another file..
superWidget.py
import widge
class superWidgety(widge.evenWidgetier):
def __init__(self, bob):
widge.widget.__init__(self,bob)
#do something
I get an error:
unbound method __init__() must be called with widget instance as first argument
Is there a way I can subclass a class from another package that works?
.
And out of curiosity, what's the deal?
Substantively this looks identical to me. I can call a class from another file by using the widge.widget(), so that method seems established. And I can subclass when the class is in the same file by referencing the class in the declaration. What is it about using a class from an import in a declaration that breaks? Why does it see itself as the right method when in the same file, but sees itself as an unbound method when imported?
The specifically, my code is this (stripping the parts that shouldn't affect this.
Attributor.py
class Tracker(object):
def __init__(self, nodeName=None, dag=None):
#Tracking stuff
class Transform(Tracker):
#Does stuff with inherited class
timeline_tab.py
import Attributor as attr
class timeline(attr.Transform):
#some vars
def __init__(self, nodeName=None):
attr.Transform.__init__(self,nodeName=nodeName)
#Additional init stuff, but doesn't happen because error on previous line
In superWidget.py change the SuperWidget to use super
import widge
class superWidgety(widge.evenWidgetier):
def __init__(self, bob):
super(SuperWidget,self).__init__(bob)
#do something
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.
In a few tutorials I've read that for __init__ method I have to do something like this:
class App:
def __init__(self):
...
However, in PySide I found this. What does the line QWidget.__init__(self) do and do I need it?
class App(QWidget):
def __init__(self):
QWidget.__init__(self)
...
Calling cls.__init__(self) (where cls can be any class), will simply call the cls's __init__ on self. Here's an example:
class Foo(object):
def __init__(self):
self.foo = True
print('Initializing object {} on Foo.__init__!'.format(self))
class Bar(object):
def __init__(self):
Foo.__init__(self)
self.bar = True
print('Initializing object {} on Bar.__init__!'.format(self))
Now creating an instance of Bar will output both __init__s:
>>> b = Bar()
Initializing object <__main__.Bar object at 0x00000000039329E8> on Foo.__init__!
Initializing object <__main__.Bar object at 0x00000000039329E8> on Bar.__init__!
Also, b now has both attributes, foo and bar.
You should rarely be calling other class's __init__, unless you're subclassing that other class. The example above is usually incorrect, since Bar is not subclassing Foo.
Even when you're subclassing a class, you shouldn't be accessing that class directly using its name, but instead use the Python's built-in function super():
# "WRONG" (usually)
class X(Y):
def __init__(self):
Y.__init__(self)
# RIGHT
class X(Y):
def __init__(self):
super().__init__() # self is omitted when using super()
This line invokes __init__ method of base class.
class App(QWidget)
App class inherits from QWidget class. Therefore, you must invoke initialize of base class when you inits instance of App class. In Python 3 you can do same thing (invoke base __init__) with
super().__init__()
In this case
class App
App class hasn't a base class.