Karls
Karls

Reputation: 751

Accessing attribute from parent class inside child class

When I access an attribute from the parent class via the child class like this all works fine:

class A():
    a=1
    b=2

class B(A):
    c=3

d=B.a+B.b+B.c
print d

But if I try to access an attribute from the parent class inside the child class like this, it doesn't work:

class A():
    a=1
    b=2

class B(A):
    c=3
    d=a+b+c
    print d

I receive the error: name 'a' is not defined

Let assume that I have many equation like d=a+b+c (but more complicated) and I can't edit them - I have to call in class B "a" as "a", not "self.a" or "something.a". But I can, before equations, do A.a=a. But it is not the smartest way to reload all variables manually. I want to bypass it using inheritance. Is it possible or i should do all manually? Or maybe it is 3th route in this code?

Upvotes: 5

Views: 6922

Answers (2)

jonrsharpe
jonrsharpe

Reputation: 122144

During the class definition, none of the inherited attributes are available:

>>> class Super(object):
    class_attribute = None
    def instance_method(self):
        pass


>>> class Sub(Super):
    foo = class_attribute



Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    class Sub(Super):
  File "<pyshell#7>", line 2, in Sub
    foo = class_attribute
NameError: name 'class_attribute' is not defined
>>> class Sub(Super):
    foo = instance_method



Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    class Sub(Super):
  File "<pyshell#9>", line 2, in Sub
    foo = instance_method
NameError: name 'instance_method' is not defined

You can't even access them using super, as the name of the subclass isn't defined within the definition block*:

>>> class Sub(Super):
    foo = super(Sub).instance_method



Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class Sub(Super):
  File "<pyshell#11>", line 2, in Sub
    foo = super(Sub).instance_method
NameError: name 'Sub' is not defined

The only way to access the inherited attributes at definition time is to do so explicitly, using the name of the superclass:

>>> class Sub(Super):
    foo = Super.class_attribute


>>> Sub.foo is Super.class_attribute
True

Alternatively you can access them within class or instance methods, but then you need to use the appropriate prefix of the class (conventionally cls) or instance (conventionally self) parameter.


* for anyone thinking "ah, but in 3.x you don't need arguments to super":

>>> class Sub(Super):
    foo = super().instance_method


Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    class Sub(Super):
  File "<pyshell#6>", line 2, in Sub
    foo = super().instance_method
RuntimeError: super(): no arguments

That's only true inside instance/class methods!

Upvotes: 9

jake77
jake77

Reputation: 2034

I may be wrong on this, but are you sure you don't want rather this?

class A(object):
    def __init__(self):
        self.a = 1
        self.b = 2


class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.c = 3

    @property
    def d(self):
        return self.a + self.b + self.c

BB = B()
print BB.d

or, as jonrsharpe pointed out:

class A():
    a=1
    b=2

class B(A):
    c=3
    d=A.a+A.b+c

print B.d

Upvotes: 4

Related Questions