Nick
Nick

Reputation: 10499

How to define correctly a subclass attribute

I have a Person class and a SubPerson sub-class:

class Person:

    def setname(self, name):
        self.name = name

    def display(self):
        print(self.name)


class SubPerson(Person):
    def display(self):
        print("Name: {0}".format(self.name))


if __name__ == "__main__":
    p = SubPerson()
    p.display()

But when I call the display method of p I have the following error:

File "./person.py", line 14, in display
    print("Name: {0}".format(self.name))
AttributeError: SubPerson instance has no attribute 'name'

Why? How can I fix this?

Upvotes: 2

Views: 160

Answers (5)

Grijesh Chauhan
Grijesh Chauhan

Reputation: 58281

Why?

You should read exception message: "AttributeError: SubPerson instance has no attribute 'name'", that clearly indicates that SubPerson's instance p that you have created in main using expression p = SubPerson() don't have attribute 'name' - that is why it throws AttributeError exception.

Lets try your code on active interpreter and see:

>>> class Person:
...  def setname(self, name):
...   self.name = name
...  def display(self):
...   print(self.name)
... 
>>> class SubPerson(Person):
...  def display(self):
...   print("Name: {0}".format(self.name))
... 
>>> p = SubPerson()
>>> p.name    # Notice 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SubPerson instance has no attribute 'name'
>>> 

Notice line p.name - you are getting same exception! Indeed p has no attribute with name 'name' you can use introspection technique to list all attribute of p using __dict__ and inherited attributes using dir() function, see below

>>> p.__dict__  
{}                 # p don't have it any it own attribute 
>>> dir(p)  # either don't inerited attribute 'name'
['__doc__', '__module__', 'display', 'setname']  
>>> 

Notice only the attributes that p inherits from Person class are 'display', 'setname' but not name.

How can I fix this?

You have few techniques to rectify your code as below:

  1. Python is dynamic language you can explicitly add new name in object namespace as:

     >>> p.name = "grijesh"
     >>> p.__dict__            # Now `p` has 'name' attributes 
     {'name': 'grijesh'}
     >>> p.display()           # it is safe to call display
     Name: grijesh
    
  2. Use your setname function as @Tasawer Nawaz's answer suggestion.

  3. Use __init__ function and implement object constructor as give in @T.C.'s answer.

Basically in all technique you are attaching 'name' attribute to SubPerson instance object before accessing it in display() function method.

Upvotes: 1

Oni1
Oni1

Reputation: 1505

class Person:
 def __init__(self, name=""):
    self.name=name

 #def setname(self, name):
 #   self.name = name

 #instead of display
 def __str__(self):
    return self.name

 #def display(self):
 #    print(self.name)

 if __name__=='__main__':
    p=Person("YourName")
    print p

You have to "initialize" your attribute of your Person object.. And i would implement the str method to print your objects its like in C++ std::operator<< ..

And your subclass looks like this:

class SubPerson(Person):
 def __str__(self):
     return "Name: {0}".format(self.name)

There are some other methods(len,get, and so on..), which you can overwrite for your own Class..

Upvotes: 4

Tasawer Nawaz
Tasawer Nawaz

Reputation: 925

please set "name" first

    p.setname("your_name")

or if you dont want to set name, then initialize name attribute in parent class

    class Person:
        name = "your_name"

Upvotes: 1

cornholio
cornholio

Reputation: 183

You should explicitly call

p.setname("name")

before accessing it

Upvotes: 0

Vor
Vor

Reputation: 35149

call the setname befoure your print statement.

Upvotes: 0

Related Questions