tags:

views:

56

answers:

4

This follows a question I asked a few hours ago.

I have this code:

class A(object):
    def __init__(self, a):
        print 'A called.'
        self.a = a

class B(A):
    def __init__(self, b, a):
        print 'B called.'

x = B(1, 2)
print x.a

This gives the error: AttributeError: 'B' object has no attribute 'a', as expected. I can fix this by calling super(B, self).__init__(a).

However, I have this code:

class A(object):
    def __init__(self, a):
        print 'A called.'
        self.a = a

class B(A):
    def __init__(self, b, a):
        print 'B called.'
        print a

x = B(1, 2)

Whose output is:

B called.
2

Why does this work? And more importantly, how does it work when I have not initialized the base class? Also, notice that it does not call the initializer of A. Is it because when I do a:

def __init__(self, b, a)

I am declaring b to be an attribute of B? If yes, how can I check b is an attribute of which class - the subclass or the superclass?

+4  A: 

The way you defined it B does not have any attributes. When you do print a the a refers to the local variable a in the __init__ method, not to any attribute.

If you replace print a with print self.a you will get the same error message as before.

sepp2k
Aah I get it now. Thanks!
Jeremy
Am I right in calling `b` an attribute of the class or is there some other Pythonic term for it?
Jeremy
Uhm, most importantly, what is the difference between 'instance variable' and 'instance attribute'?
Jeremy
@Jeremy: `__init__` is just a function, like any other. `b` is just an argument of that function. Nowhere is `b` set to be an attribute of anything. It's only when you do e.g. `self.a = a` that you define an instance attribute (aka instance variable).
katrielalex
+2  A: 

In your second code, calling print a works because you are printing the variable passed as a parameter to B's __init__ function, not the self.a variable (which is not initialized because A.__init__ was not called). Once you leave the scope of the __init__ function you will loose access to the a.

Federico Cáceres
So `a` is akin to a class attribute?
Jeremy
+1  A: 

The short answer is that __init__ isn't a constructor in the sense of other languages, like C++. It's really just a function that runs on an object after the "bare" object is created. B's __init__ function is conventionally responsible for calling A's __init__, but it doesn't have to - if A.__init__ never gets called, then then A's attribute a doesn't get added to the object, and so you get an error when you try to access it.

Doug
+1  A: 

To fix this problem, you'll need to use

class B(A):
    def __init__(self, b, a):
        super(A, self).__init__(a)

Make sure you declare the classes as new style objects, something you're already doing

[edit: clarification]

You mean't `super(B, self).__init__(a)` I guess :)
sukhbir