0

When I run this code. I get the following errors

Traceback (most recent call last): File "C:/Users/Nabeel Hussain Syed/PycharmProjects/Hello World/check.py", line 80, in print(spot.toString()) File "C:/Users/Nabeel Hussain Syed/PycharmProjects/Hello World/check.py", line 66, in toString return "{} is {} cm tall and {} kilograms and say {}. His owner is {}".format(self.__name, AttributeError: 'Dog' object has no attribute '_Dog__name'

Open the link of the image to check out the errors.

    class Animal:
    __name = None
    __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 set_name(self, name):
        self.__name = name

    def set_height(self, height):
        self.__height = height

    def set_weight(self, weight):
        self.__weight = weight

    def set_sound(self, sound):
        self.__sound = sound

    def get_name(self):
        return self.__name

    def get_height(self):
        return str(self.__height)

    def get_weight(self):
        return str(self.__weight)

    def get_sound(self):
        return self.__sound

    def get_type(self):
        print("Animal")

    def toString(self):
        return "{} is {} cm tall and {} kilograms and say {}".format(self.__name,
                                                            self.__height,
                                                            self.__weight,
                                                            self.__sound)

cat = Animal('Whiskers', 33, 10, 'Meow')
print(cat.toString())

class Dog(Animal):
    __owner = ""

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

    def set_owner(self, owner):
        self.__owner = owner

    def get_owner(self):
        return self.__owner

    def get_type(self):
        print("Dog")

    def toString(self):
        return "{} is {} cm tall and {} kilograms and say {}. His owner is {}".format(self.__name,
                                                            self.__height,
                                                            self.__weight,
                                                            self.__sound,
                                                            self.__owner)


    def multiple_sounds(self, how_many=None):
        if how_many is None:
            print(self.get_sound())
        else:
            print(self.get_sound() * how_many)

spot = Dog("Spot", 53, 27, "Ruff", "Derek")
print(spot.toString())
  • 2
    Please, *please*, don't use that "convention". Python is not Java, don't force it. Use properties if you have to control assignment from outside the class. – DeepSpace Aug 10 '17 at 14:33

2 Answers2

0

Attributes with names starting with double underscores are considered "private", and not accessible from child classes. You could still access them by names like _Animal__name (Animal is a parent class name in which attribute was defined), but it's a bad practice.

More information in official documentation: https://docs.python.org/3.6/tutorial/classes.html#private-variables

bakatrouble
  • 1,746
  • 13
  • 19
0

the double-underscore has significance in Python. Please see this excerpt from a previous stack overflow answer:

Double leading underscore

This one actually has syntactical significance. Referring to self.__var1 from within the scope of your class invokes name mangling. From outside your class, the variable will appear to be at self._YourClassName__var1 instead of self.__var1. Not everyone uses this - we don't at all where I work - and for simple classes it feels like a slightly absurd and irritating alternative to using a single leading underscore.

However, there is a justification for it existing; if you're using lots of inheritance, if you only use single leading underscores then you don't have a way of indicating to somebody reading your code the difference between 'private' and 'protected' variables - ones that aren't even meant to be accessed by subclasses, and ones that subclasses may access but that the outside world may not. Using a single trailing underscore to mean 'protected' and a double underscore to mean 'private' may therefore be a useful convention in this situation (and the name mangling will allow a subclasses to use a variable with the same name in their subclass without causing a collision).

Tom Sitter
  • 1,082
  • 1
  • 10
  • 23
  • Thank you very much. I completely understand now. I was following a video as I'm a newbie to Python in which the guy named the same variables and he wasn't getting any errors. – Nabeel Hussain Aug 10 '17 at 14:43