5

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)

Trufa
  • 39,971
  • 43
  • 126
  • 190

3 Answers3

12

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)
Boldewyn
  • 81,211
  • 44
  • 156
  • 212
  • 1
    To further clarify, you must inherit from `object` in 2.x. In 3.x, [old-style classes go away](http://stackoverflow.com/questions/1238606/is-it-necessary-or-useful-to-inherit-from-pythons-object-in-python-3-x), so inheriting from `object` is unnecessary. – senderle May 26 '11 at 19:19
  • @senderle: True, thanks. I should start to respect 3 more and not take it as given, that 2.x is used. – Boldewyn May 26 '11 at 19:25
  • I haven't yet understood how to use `super()`, wasn't [this](http://pastie.org/1977636) what you suggested. – Trufa May 26 '11 at 19:25
  • @Bolderwyn, I'm struggling to do that myself -- hence the comment. :) – senderle May 26 '11 at 19:26
  • @Trufa: no, I made the same mistake, when I first started to use it. The first argument to super() is *the own class*, in the pastie example, `Two`. Think of it this way: super() *returns* the super-class of its first argument. – Boldewyn May 26 '11 at 19:27
  • By the way, in this way you can also call methods of super-super-classes all the way up the inheritance chain. If One inherits from Zero and isinstance(self, Two), `super(One, self).__init__` is the method of the class Zero. – Boldewyn May 26 '11 at 19:30
  • @Boldewyn: No I'm even more confused! :) you say like this? `def __init__(self): super(Two, self).__init__()` (I say that what you suggest is in the docs, but I'm not figuring out somthing) – Trufa May 26 '11 at 19:32
  • @Trufa, I wrote a long comment that wound up reproducing what Bolderwyn has already said. So I'll just add that this is why I suggested getting used to inheritance before trying to use `super`. :) – senderle May 26 '11 at 19:37
  • 1
    Read this just the other minute via delicious: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ – Boldewyn May 26 '11 at 19:37
  • @senderle: I am actually using you method, but just trying to understand that for later. Thank for all the help! – Trufa May 26 '11 at 19:53
  • @Boldewyn: hmm ok but its not working that, way. I'm confused... I'll take another shot at it but I'll have @senderle 's advice in mind. – Trufa May 26 '11 at 19:55
4

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.

Community
  • 1
  • 1
senderle
  • 145,869
  • 36
  • 209
  • 233
  • Thank you very much, I'm sure this is obvious, but you have to learn it at some point I guess :) +1 for first and correct answer! – Trufa May 26 '11 at 19:14
2

You forgot to initialize the superclass.

class Score(Play):
  def __init__(self):
    super(Score, self).__init__()
    self.initialScore = 0
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358