Search code examples
pythoninheritanceclass-variables

Access local classvariable from inherited instance


I have my pseudo Interface, which I implement several times. Each implementation is supposed to store a variable that basically defines a path to a file (a template). Because these classes are produced by a factory, I don't know which subclass is going to come up, therefore, I want to make it possible to access a class variable via an instance method.

This does not really pose a problem, however, when I inherit from my Interface, I don't want to implement the getHidden() method (in the following) several times. But calling it, the way it is written down there, will always yield hidden.

class MySuperInterface(object):
    # class Variable
    __much = "hidden"

    # instance method
    def getHidden(self):
        print self.__class__.__much

class MySub(MySuperInterface):
    __much = "this is different per subclass!"

    def soTroublesome(self):
        print self.__class__.__much

Execution

>>> sub = MySub() # I don't know this class!

>>> sub.getHidden()
hidden

>>> sub.soTroublesome()
this is different per subclass!

So, how can I implement getHidden() to access the instance's class' classvariable. I know, that the information is available, as I checked with dir(), but I have no idea how to access it. Again, I don't want to end up with a class/static method, because I don't know the class that gets out of my factory!

Thanks!


Solution

  • Just don't use the "__" in the class variable name and you are set.

    Some Python write ups and "documentation" say that the "__" prefix is the Python way to get "private" members in a class. They are wrong.

    The "__" prefix does exactly what is happening to you: ensure that the variable accessed in a method inside a class access the variable defined in that exact class (and not any of the classes that inherit from it).

    The way it works is simple: at compile time, the names prefixed with "__" are "mangled", i.e. changed like this: __much -> _classname__much:

    >>> class Hidden(object):
    ...   __hidden = False
    ... 
    >>> dir(Hidden)
    ['_Hidden__hidden', '__class__',  ...]
    

    Therefore your getHidden method will always look for the __much variable thathas had its name actually changed to _MySuperInterface__much, while the variable you want has had its name changed to _MySub__much.

    If you as much as use a single underscore "_" to mean by convention the variable should not be used outside of the class, your code would work as you expect.