I'm just starting out with Python, but I cannot figure out why I'm having a problem with such simple class inheritance, and despite the common use of the tutorial I've been following, I haven't seen anyone else on Stack Overflow encountering this issue. Here's the code (don't worry, nothing too complicated):
import random
import sys
import os
class Animal:
__name = ""
__height = 0
__weight = 0
__sound = 0
def __init__(self, name, height, weight, sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
def toString(self):
return "{} is {} cm tall and {} kilograms and says {}".format(self.__name,
self.__height,
self.__weight,
self.__sound)
cat = Animal ('Whiskers', 33, 10, 'meow')
print(cat.toString())
bird = Animal ('Flutie', 33, 10, 'tweet')
print(bird.toString())
class Dog(Animal):
def __init__(self, name, height, weight, sound):
super(Dog, self).__init__(name, height, weight, sound)
def toString(self):
return "{} is {} cm tall and {} kilograms and says {}".format(self.__name,
self.__height,
self.__weight,
self.__sound)
spot = Dog ('Spot', 53, 27, "Woof")
print(spot.toString())
...And here's the output:
Whiskers is 33 cm tall and 10 kilograms and says meow
Flutie is 33 cm tall and 10 kilograms and says tweet
Traceback (most recent call last):
File "C:/.../animal_test.py", line 72, in <module>
print(spot.toString())
File "C:/.../animal_test.py", line 65, in toString
return "{} is {} cm tall and {} kilograms and says {}".format(self.__name,
AttributeError: 'Dog' object has no attribute '_Dog__name'
The double underscores represents name mangling.
class Animal:
def __init__(self, name, height, weight, sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
Literally translates to this when being interpreted:
class Animal:
def __init__(self, name, height, weight, sound):
self._Animal__name = name
self._Animal__height = height
self._Animal__weight = weight
self._Animal__sound = sound
It doesn’t matter where it’s called, or who called the __init__
, the prefix _Animal
will take place because it’s physically located under the Animal
class.
But when you used the attributes here, as it’s physically located under the Dog
class, the got name mangled to this:
class Dog(Animal):
def __init__(self, name, height, weight, sound):
super(Dog, self).__init__(name, height, weight, sound)
def toString(self):
return "{} is {} cm tall and {} kilograms and says {}".format(self._Dog__name,
self._Dog__height,
self._Dog__weight,
self._Dog__sound)
Which the Dog
object definitely doesn’t have an attribute named self._Dog__name
, instead it has the attribute self._Animal__name
.