简体   繁体   中英

Attribute Error while using super() in Python 3.5

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.

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)

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 , ie adding _ClassName in front of all attributes with two leading underscores. This prevents the inheritance you do from working.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM