0

This is a piece of Python code to learn inheritance.

class Animal():
    __name= None
    __sound = None

    def __init__(self, name , sound):
        self.__name= name
        self.__sound = sound 
    def ToString(self):
        print ("The {} has the sound  {}".format(self.__name ,
                                                self.__sound))


cat = Animal('Tiger' , 'roars')
cat.ToString()


class Panther(Animal):
    __owner = None

    def __init__(self , name ,sound ,owner):
        self.__owner = owner
        super(Panther ,self).__init__(name, sound)
    def ToString(self):
        print(self.__owner)
        print(self.__name) 

leopard = Panther('Leopard' , 'roars' , 'Senegal')
leopard.ToString()

But when I try to run it in Pycharm, I get the following error:

/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/venkat/PycharmProjects/PythonOneVideo/main.py The Tiger has the sound roars Senegal Traceback (most recent call last): File "/Users/venkat/PycharmProjects/PythonOneVideo/main.py", line 41, in leopard.ToString() File "/Users/venkat/PycharmProjects/PythonOneVideo/main.py", line 35, in ToString print(self.__name) AttributeError: 'Panther' object has no attribute '_Panther__name'

Process finished with exit code 1

What's wrong with calling the super class constructor? Why this error has happened and how to solve this? Any help would be appreciated.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
athavan kanapuli
  • 462
  • 1
  • 6
  • 19
  • Possible duplicate of [The meaning of a single- and a double-underscore before an object name in Python](http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python) – Łukasz Rogalski Jan 02 '17 at 10:06

3 Answers3

4

several issues:

  • python 3 syntax for super: super().__init__(name, sound)
  • name mangling: instance variables starting with __ (two underscores) will get _ClassName prepended to them. child classes will not be able to access them the usual way.
  • ToString: why not __str__ (and do not print inside __str__; just return a str)?
  • and what are the class variables (_name etc) for? why not just have them as instance variables (self._name)?

this works bus is incomplete...

class Animal():
    # _name= None
    # _sound = None

    def __init__(self, name , sound):
        self._name= name
        self._sound = sound

#    def ToString(self):
#        print ("The {} has the sound  {}".format(self._name ,
#                                                self._sound))

    def __str__(self):
        fmt = 'The {self._name} has the sound {self._sound}'
        return fmt.format(self=self)

cat = Animal('Tiger' , 'roars')
print(cat)

class Panther(Animal):
    # _owner = None

    def __init__(self , name ,sound ,owner):
        self.__owner = owner
        super().__init__(name, sound)

#    def ToString(self):
#        # print(self._owner)
#        print(self._name)

leopard = Panther('Leopard' , 'roars' , 'Senegal')
print(leopard)
hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
1

Remove the two leading underscore from your attributes:

class Animal():
    name= None
    sound = None

    def __init__(self, name , sound):
        self.name= name
        self.sound = sound 
    def ToString(self):
        print ("The {} has the sound  {}".format(self.name ,
                                                self.sound))


cat = Animal('Tiger' , 'roars')
cat.ToString()


class Panther(Animal):
    owner = None

    def __init__(self , name ,sound ,owner):
        self.owner = owner
        super(Panther ,self).__init__(name, sound)
    def ToString(self):
        print(self.owner)
        print(self.name) 

leopard = Panther('Leopard' , 'roars' , 'Senegal')
leopard.ToString()

Output:

The Tiger has the sound  roars
Senegal
Leopard

The two leading underscores make your attributes "private". This is done my name mangling, i.e. adding _ClassName in front of all attributes with two leading underscores. This prevents the inheritance you do from working.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
0

Your error stems from the name mangling Python performs when you prepend a variable name with __. If you simply use names without the double trailing underscores, this works fine:

class Animal():
    def __init__(self, name , sound):
        self._name= name
        self._sound = sound 
    def ToString(self):
        print ("The {} has the sound  {}".format(self._name ,
                                                self._sound))


cat = Animal('Tiger' , 'roars')
cat.ToString()


class Panther(Animal):

    def __init__(self , name ,sound ,owner):
        self._owner = owner
        super(Panther ,self).__init__(name, sound)
    def ToString(self):
        print(self._owner)
        print(self._name)

and prints out:

>>> leopard = Panther('Leopard' , 'roars' , 'Senegal')
>>> leopard.ToString()
The Tiger has the sound  roars
Senegal
Leopard
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253