Search code examples
pythonpython-2.7classgetter-setter

How to access Magic Methods inside a Class python


I am having hard time understanding this. Let's say we have a snippet of code as such

class Animal:
        def __init__(self, name, food):
                self.name = name
                self.__food = food
        def getFood(self):
                return self.__food

Then we initialize it

>>> animal = {}
>>> animal["dog"] = Animal("rusty", "delicious thing you never know")

Now, while accessing the attributes, It seems to not let me access __food

>>> animal["dog"].name
'rusty'
>>> animal["dog"].__food
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Animal instance has no attribute '__food'

Why does that fail. As we can clearly see I am using self.__food = food where __ is magic method. So how do I print the __food Magic attribute ?


Solution

  • The primary purpose of adding leading underscores is to provide something akin to "private variables" in python. Well, they aren't exactly private variables - python does not really provide this language feature. The interpreter will mangle the names, making it (slightly) harder to access these members from outside the class.

    You may read more on the official documentation (2.x docs since your question is tagged as such). Relevant excerpt -

    Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

    To summarise, the mangled version of a "private" variable, say __x will be _ClassName__x. You can verify this is the case for your class:

    In [251]: animal['dog']._Animal__food
    Out[251]: 'delicious thing you never know'
    

    Right, so, as mentioned in my comment, the purpose of a "private member" is so that it may not be accessed outside the class. If your intention with defining this member is so that it should be accessed outside, you shouldn't even be adding the leading underscores.