I'm wondering about this issue I'm getting with Python, I'm sure this is well known. I've been dabbling in Python now for a while and am getting used to it's flavor but I'm running into this issue outlined below. If you run this code below:
import pprint
pp = pprint.PrettyPrinter(indent=4).pprint
class Foo(object):
def __init__(self):
self.foo_var = 1
class Bar(Foo):
def __init__(self):
self.bar_var = 2
super(Foo, self).__init__()
def deep_access(self):
pp(self.bar_var)
class FooBar(Bar):
def __init__(self):
self.foobar_var = 3
super(Bar, self).__init__()
def access(self):
# call Bar
self.deep_access()
fb = FooBar()
fb.access()
You will receive the following error:
Traceback (most recent call last):
File "inheritance.py", line 29, in <module>
fb.access()
File "inheritance.py", line 26, in access
self.deep_access()
File "inheritance.py", line 16, in deep_access
pp(self.bar_var)
AttributeError: 'FooBar' object has no attribute 'bar_var'
From the error I gather it's looking for bar_var in FooBar rather than Bar, but if I call the parent class, why not use the variable declared in the parent?? How do I get a parent class to access it's own variables? It just seems weird to me coming from a different approach to OOP.
Instead of self.deep_access it tried Bar.deep_access(self) and super(FooBar, self).deep_access and super(Bar, self).deep_access and it doesn't work.
You are not calling super() correctly. The first argument should always be the class that's calling super, not any of its base classes..
change
class Bar(Foo):
def __init__(self):
self.bar_var = 2
super(Foo, self).__init__()
# ^^^
to
class Bar(Foo):
def __init__(self):
self.bar_var = 2
super(Bar, self).__init__()
# ^^^
and so on...
There's a nice article explaining most of the ins and outs of super() called "Super considered Super!"
Related
I have a superclass that uses some properties from the child class.
but unless I define properties in my superclass ALSO then the linter throws errors.
what's a pythonic way to get around this?
# parent
class DigItem:
def fetch_bq(self):
query = f'''select * from {self.table_id}'''
# subclass
class ChatLog(DigItem):
def __init__(self, set_name):
super().__init__(set_name)
self.table_id = biglib.make_table_id('chat_logs')
The above code errors with:
Instance of 'DigItem' has no 'table_id' memberpylint(no-member)
now, I can add the property to the superclass but that's pretty redundant and also risks overwriting the subclass
class DigItem:
def __init__(self, set_name):
self.table_id = None # set by child
This is down to the linter not being able to know AOT that this is a 'superclass' so it's fair enough as an error in a standalone instance.
But I'd prefer clean linting, pythonic code and not writing special hacky stuff just to shut up the linter.
In your example, DigItem has no __init__ at all (so it will be object's), so passing an argument to super().__init__() will fail
>>> class A: pass
...
>>> class B(A):
... def __init__(self):
... super().__init__("something")
...
>>> B()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: object.__init__() takes exactly one argument (the instance to initialize)
Further, you should (must) create the missing property in your parent in order for it to meaningfully make use of it in a method (otherwise different inheriting classes will not be able to make use of the method)
>>> class A:
... def foo(self):
... return self.bar
...
>>> class B(A):
... def __init__(self):
... self.bar = "baz"
...
>>> class C(A): pass # NOTE .bar is never defined!
...
>>> C().foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
AttributeError: 'C' object has no attribute 'bar'
If the base class is not intended to be directly instantiable, consider making it an Abstract Base Class
edit : Problem solved, I was indeed a idiot and it was indeed a very silly mistake. The solution was that I forgot to give an instance of UI when creating a Joueur instance... Sorry and thanks to all who tried to help me.
I've been trying to code a chess game. I am now in the process of testing it and I got a "weird" error (from my experience I probably just messed up, but my situation is not exactly what people on every other post on this error seem to be and I have been searching my code and documentation for clues for some hours with no success : so here I am).
So to summarize the code (I won't put code I have successfully run before and will only show what should be relevant):
I have a board class which is basically my model and my controller. In the constructor I ask for arguments two players, a UI class, and a hash class. Before I implemented the last two, and added it in the constructor, the code ran just fine.
class Plateau:
def __init__(self, j1, j2, UI, Hash):
self.UI = UI
self.UI.ajoutePlateau(self)
self.Hash = Hash
self.Hash.hashPlateau(self)
# some code to deal with the rest
...
#
self.UI.initAffichage()
I then have a UI interface and a ConsolUI (UITerminal in my code) which inherit from it. It is as expected what show to the user the board and also what ask the human player (if there is one) what he wants to play.
class UI:
def __init__(self):
self.Plateau = None
def ajoutePlateau(self, Plateau):
self.Plateau = Plateau
# a bunch of method that throw an exception and are overrided by the child class
...
#
class UITerminal(UI):
def __init__(self):
#super(UITerminal, self).__init__(self)
#super().__init__(self)
#UI.__init__(self)
#super(UITerminal, self).__init__()
super().__init__()
#UI.__init__()
# the method that had to be overridden
...
#
I have also tried few version of the UITerminal constructor (which are above and put on comment).
or even just nothing since it should not even be needed (I think...).
Then there is the hash, which is build the same way as the UI : an interface, a child.
class Hash:
def __init__(self):
pass
# a bunch of method that throw an exception and are overridden by the child class
...
#
class ZombristHash(Hash):
def __init__(self):
#super(ZombristHash, self).__init__(self)
#super().__init__(self)
#Hash.__init__(self)
#super(ZombristHash, self).__init__()
super().__init__()
#Hash.__init__()
# a bunch of code to init the zombristhash
...
#
same as with the UI, I tried multiple way to call the interface constructor.
Then I have my main, which is only 1 line and is what throw the error :
p = Plateau(Humain("j1"), Humain("j2"), UITerminal(), ZombristHash())
and the error is :
Traceback (most recent call last): File "plateau.py", line 298, in <module> p = Plateau(Humain("j1"), Humain("j2"), UITerminal(), ZombristHash())
TypeError: __init__() missing 1 required positional argument: 'UI'.
From what I understand, he tells me I haven't given the board constructor a UI as argument, but I did so I do not understand what is happening.
I tried on quamran's suggestion this :
p = Plateau(None, None, None, None)
And it seems to think it was ok now...
Traceback (most recent call last):
File "plateau.py", line 298, in <module>
p = Plateau(None, None, None, None)
File "plateau.py", line 13, in __init__
self.UI.ajoutePlateau(self)
AttributeError: 'NoneType' object has no attribute 'ajoutePlateau'
As #Jacques Gaudin noticed, you need to change this :
class ZombristHash(Hash):
def __init__(self):
Hash.__init__()
to this :
class ZombristHash(Hash):
def __init__(self):
super().__init__()
and same for UI.
Finally, you get something like this :
class Plateau:
def __init__(self, j1, j2, UI, Hash):
self.UI = UI
self.UI.ajoutePlateau(self)
self.Hash = Hash
class Hash:
def __init__(self):
pass
class ZombristHash(Hash):
def __init__(self):
super().__init__()
class UI:
def __init__(self):
self.Plateau = None
def ajoutePlateau(self, Plateau):
self.Plateau = Plateau
class UITerminal(UI):
def __init__(self):
# super(UITerminal, self).__init__()
super().__init__()
class Humain():
def __init__(self, j):
pass
p = Plateau(Humain("j1"), Humain("j2"), UITerminal(), ZombristHash())
Using python 2.7
I'm creating a library of objects on import using decorators, and while importing I do some checks on the instance of each object; mostly duplication checks...
I've recently made the switch to using super() to take advantage of its multiple-inheritance handling, but it raises a NameError on the object being instantiated.
Simplified code highlighting issue:
class Lib(object):
def __init__(self):
print "library created"
self.lib = {}
def add_obj(self, obj):
print "object being added to library --> %s" % obj.__name__
inst = obj()
print inst.name
self.lib[obj.__name__] = obj
def Reg(obj):
global test_lib
test_lib.add_obj(obj)
test_lib = Lib()
#Reg
class A(object):
def __init__(self):
object.__init__(self)
self.name = "A instance"
#Reg
class B(object):
def __init__(self):
super(B, self).__init__()
self.name = "B instance"
Output
>>> from testing import *
library created
object being added to library --> A
A instance
object being added to library --> B
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "testing.py", line 25, in <module>
class B(object):
File "testing.py", line 14, in Reg
test_lib.add_obj(obj)
File "testing.py", line 8, in add_obj
inst = obj()
File "testing.py", line 27, in __init__
super(B, self).__init__()
NameError: global name 'B' is not defined
It seems like there's a scoping issue? Excluding the decorator, class B instantiates without a problem.
Any suggestions?
You are attempting to instantiate B before it has finished being defined.
Fix it:
Remove these lines from Lib.add_obj():
inst = obj()
print inst.name
Why?
The decorator Reg is involved in the definition of B. So you will not be able to instantiate B, via that name, until Reg has exited.
I am trying to subclass ConfigParser. When trying to access _sections it says
'acc' object has no attribute '_sections'
Example Code(python 2.7):
import ConfigParser
class acc(object, ConfigParser.RawConfigParser):
def __init__(self, acc_file):
super(acc,self).__init__()
self.lol = 1
print self.has_section(self.lol)
a=acc(1)
The problem has been described much better here.
This is Python's Method Resolution Order.
So, what actually happens is that the MRO "chaining" does not behave well when encoutering an old style class. Or to be specific - classes that do not call super
In your code, configParser.RawConfigParser__init__(..) is never called. To fix this you could call it manually (simply add ConfigParser.RawConfigParser.__init__(self ...) in acc's init), although I'm not sure this is recommended or even valid.
Your other option is to make all classes conform to the new style, and invoke super, or old style, and initialize explicitly.
The only thing that seems to be working is if all classic-style classes are after all new-style classes in the output of Class.mro(), and specifically after object. This will prevent super from calling them.
The other answer isn't very safe because of this scenario:
class TheClassicClass:
def __init__(self):
print "instantiating clasic class!"
self._msg = "the classic class!"
def m(self):
print self._msg
class acc(ConfigParser.RawConfigParser, TheClassicClass, object):
def __init__(self, acc_file):
super(acc,self).__init__()
self.lol = 1
print self.has_section(self.lol)
a=acc(1)
a.m()
Fix to other answer: adding these lines to acc's __init__ should inform to explicitly instantiate the classes:
ConfigParser.RawConfigParser.__init__(self)
TheClassicClass.__init__(self)
To confirm the problem in your code, let's try to reproduce this problem in a simple setup...
We'll make old (classic) classes:
class AClassic:
def __init__(self):
print "init aclassic"
class BClassic:
def __init__(self):
print "init bclassic"
self.name = "bclassic"
def m(self):
print "print from " + self.name
And new style classes that invoke super:
class ANew(object):
def __init__(self):
print "init anew"
super(ANew, self).__init__()
class BNew(object):
def __init__(self):
print "init bnew"
super(BNew, self).__init__()
def m(self):
print "print from bnew"
In the simplest case, we're manually calling __init__ to make sure classes are instantiated. This would look something like:
class TestOldStyle(AClassic, BClassic):
def __init__(self):
AClassic.__init__(self)
BClassic.__init__(self)
self.m()
print "old style"
TestOldStyle()
In this case, depth-first, left-to-right, is the order of the MRO.
Output:
old style
init aclassic
init bclassic
print from bclassic
Now let's try new style, which looks like this with super:
# will init ANew and BNew
class TestNewSuper(ANew, BNew, object):
def __init__(self):
super(TestNewSuper, self).__init__()
TestNewSuper()
Since both classes call super, they are both instantiated and the output is:
init anew
init bnew
Now, we try using some "hybrids" of a classic-style classes (ConfigParser.RawConfigParser is a classic-style-class, and cannot call super:
# will init ANew , but not BClassic
class TestOldStyleSuper(ANew, BClassic):
def __init__(self):
super(TestOldStyleSuper, self).__init__()
self.m()
Output:
init anew
And immediately an exception:
Traceback (most recent call last):
File "./inhert.py", line 35, in <module>
TestOldStyleSuper()
File "./inhert.py", line 33, in __init__
self.m()
File "./inhert.py", line 15, in m
print "print from " + self.name
AttributeError: 'TestOldStyleSuper' object has no attribute 'name'
This happens since BClassic is not instantiated.
More examples of unexpected behaviour:
# init ANew, BClassic
class TestHybrid(ANew, BClassic, BNew):
def __init__(self):
super(TestHybrid, self).__init__()
self.m()
TestHybrid()
will initialize ANew and BClassic, but not BNew:
init anew
init bclassic
print from bclassic
And creating an incosistent MRO:
# no consistent MRO exception
class TestHybrid(ANew, object, BNew):
def __init__(self):
super(TestHybrid, self).__init__()
self.m()
TestHybrid()
Exception:
Traceback (most recent call last):
File "./inhert.py", line 33, in <module>
class TestHybrid(ANew, object, BNew):
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases BNew, object
Reverse the order of subclassing as follows:
import ConfigParser
class acc(ConfigParser.RawConfigParser, object):
def __init__(self, acc_file):
super(acc, self).__init__()
self.lol = 1
print self.has_section(self.lol)
a=acc(1)
I can't really understand what I'm doing wrong, since when I try it in "small scale" and it is working there.
I have a class named Play()
I goes like this:
class Play():
def __init__(self):
file = open("/home/trufa/Desktop/test", "r")
self.word = random.choice(file.readlines()).rstrip()
self.errAllowed = 7
self.errMade = 0
self.errList = []
self.cheatsAllowed = 2##chetas not incrementing
self.cheatsMade =0
self.wordList = ["*"]*len(self.word) ##this one is the one I want to have available in another class
...
Then I have another class called Score()
class Score(Play):
def __init__(self):
self.initialScore = 0
def letterGuess(self):
self.initialScore += 1
return self.errList
...
I instantiated both:
game = Play()
points = Score()
And if I do:
print points.letterGuess()
It gives me an error:
Traceback (most recent call last):
File "/home/trufa/workspace/hangpy/src/v2.py", line 188, in <module>
startGame()
File "/home/trufa/workspace/hangpy/src/v2.py", line 134, in startGame
print points.letterGuess()
File "/home/trufa/workspace/hangpy/src/v2.py", line 79, in letterGuess
return self.errList
AttributeError: Score instance has no attribute 'errList'
I don't understand why since I can do this without any trouble:
class One():
def __init__(self):
self.list= [1,2]
class Two(One):
def meth(self):
return self.list
uan = One()
tu = Two()
print uan.list
print tu.meth() ## Both output [1,2]
I'm very new to OOP so I could be doing all kinds of silly mistakes but I can't figure out where!
I think I have posted all the relevant code, but I you think the error might be elsewhere, I can provide it.
As I said I'm very new, so this might have nothing to do with inheritance I just think it called that when you get "something" from within another class (you must be shouting at the screen by now)
You overwrite the original __init__, which is then never called and doesn't initialize the members. You must call the parent's __init__ separately, usually with this snippet:
def __init__(self):
super(Score, self).__init__()
See the docs for super() for details. However, super() only works for so-called new-style classes. You must therefore either change the definition of Play to inherit from object:
class Play(object)
or you call the parent's method directly:
def __init__(self):
Play.__init__(self)
When you inherit from the class Play, you automatically get the attributes that you've created in the definition of Play, but you don't get the attributes that you've created in Play.__init__. You have to explicitly call it like so:
class Score(Play):
def __init__(self):
Play.__init__(self)
self.initialScore = 0
See Boldewyn's suggestion for using super to do this; but IMO you should probably get used to the basic way inheritance works before fiddling with super.
To further clarify, if you don't override __init__ as you have in this case, then it's inherited and called automatically.
You forgot to initialize the superclass.
class Score(Play):
def __init__(self):
super(Score, self).__init__()
self.initialScore = 0