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)
Related
I am trying to do the following in python3:
class Parent:
#classmethod
def show(cls, message):
print(f'{message}')
#classmethod
def ask(cls, message):
cls.show(f'{message}???')
class Child(Parent):
#property
def name(self):
return 'John'
def show(self, message):
print(f'{self.name}: {message}')
instance = Child()
instance.ask('what')
But it then complains
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in ask
TypeError: Child.show() missing 1 required positional argument: 'message'
even so child.show works as expected. So it seems that child.ask is calling Parent.show... I tried to mark Child.show as classmethod too, but then the cls.name is not showing the expected output:
class Child2(Parent):
#property
def name(self):
return 'John'
#classmethod
def show(cls, message):
print(f'{cls.name}: {message}')
instance2 = Child2()
instance2.ask('what')
this shows
<property object at 0xfc7b90>: what???
Is there a way to override a parent classmethod with a non-classmethod, but keeping other parent classmethod to call the overridden one?
I found it hard to follow for the second half of the question but there was an issue I saw and it might help you solve your problem.
When you said even so child.show works as expected. So it seems that child.ask is calling Parent.show, thats not what is happening.
When you called instance.ask("what"), it called the #classmethod decorated method of the Child class (which is inherited from the parent). This ask method is passing the class Child as the first argument, (not the instance you created). This means the line
cls.show(f'{message}???')
is equivalent to
Child.show(f'{message}???') # because cls is the Class not the instance
The show method inside the Child class is an instance method and expects the first argument to be the actual instance (self) but the string f'{message}???' is being passed to it and it expects a second message string to be passed so that's why its is throwing an error.
Hope this helped
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!"
Im trying to write a simple setup to call a parent class #classmethod but getting error's...Please let me know what is the issue here?
class Parent(object):
def __init__(self):
print "Parent initialized"
#classmethod
def resource_setup(cls):
print "parent method"
class Child(Parent):
def __init__(self):
print "Child initialized"
#classmethod
def childmethod(cls):
super(Parent, cls).resource_setup()
print "child method"
c = Child()
Child().childmethod()
Output:
Child initialized
Child initialized
Traceback (most recent call last):
File "C:\Users\ANAND\workspace\Scratch\Scratch\Parent.py", line 30, in <module>
Child().childmethod()
File "C:\Users\ANAND\workspace\Scratch\Scratch\Parent.py", line 25, in childmethod
super(Parent, cls).resource_setup()
AttributeError: 'super' object has no attribute 'resource_setup'
Question:
1. When I create a child object c = Child(), I don't see the display of "parent initialized"..I expect the Parent class to be initialized.
2.How can I call the parent method #classmethod from the child #classmethod?
You need to call super(Child, cls). The first argument to super should be the class whose superclass you want to call the method on, not the superclass itself.
Your question 1 is unrelated. If you want the child __init__ to call the parent __init__, you need to do so explicitly using super, just as you did with parentmethod and childmethod. (That is, do super(Child, self).__init__() from within the child's __init__.
When I create a child object c = Child(), I don't see the display of "parent initialized"..I expect the Parent class to be initialized.
A: In python, derived class's __init__ does not call the base class's __init__ implicitly, you need to call it explicitly. Not as the constructor in c++ do, which may cause a bit confuse if you are a c++ programer.
How can I call the parent method #classmethod from the child #classmethod?
A: Use super(Child, cls) not super(Parent, cls).
I'm not sure why this is happening. It seems to think that "self" requires an argument, which doesn't make any sense.
Here's my code:
class Animal:
def __init__(self):
self.quality = 1
class Bear(Animal):
def __init__(self):
Animal.__init__(self)
def getImage(self):
return "bear.ppm"
class Fish(Animal):
def __init__(self):
Animal.__init__(self)
def getImage(self):
return "fish.ppm"
And the error I get is:
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
Bear.getImage()
TypeError: getImage() takes exactly 1 argument (0 given)
You have to instantiate Bear before you call getImage():
b = Bear()
b.getImage()
getImage is an instance method, so it is only designed to be called on a specific instance of the Bear class. The state of that instance is what is passed as the self variable to getImage. Calling b.getImage() is equivalent to this:
b = Bear()
Bear.getImage(b)
So, without an instance of Bear, there is nothing that can be used for the self argument, which is why you see that exception when you called Bear.getImage(). See the documentation on Python instance methods for more information.
If you want to be able to call getImage on the class Bear rather than on a specific instance, you need to make it a static method, using the #staticmethod decorator:
class Bear(Animal):
def __init__(self):
Animal.__init__(self)
#staticmethod
def getImage():
return "bear.ppm"
Then you could call Bear.getImage().
getImage() is an instance method, so it can only be called with a instantiation of Bear class. So here is how you can do it:
Bear().getImage()
or
be = Bear()
be.getImage()
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