Search code examples
pythonpython-3.xscopename-mangling

How to access private variable of Python module from class


In Python 3, prefixing a class variable makes it private by mangling the name within the class. How do I access a module variable within a class?

For example, the following two ways do not work:

__a = 3
class B:
    def __init__(self):
        self.a = __a
b = B()

results in:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
NameError: name '_B__a' is not defined

Using global does not help either:

__a = 3
class B:
    def __init__(self):
        global __a
        self.a = __a
b = B()

results in:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
NameError: name '_B__a' is not defined

Running locals() shows that the variable __a exists unmangled:

>>> locals()
{'__package__': None, '__name__': '__main__',
 '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
 '__doc__': None, '__a': 3, 'B': <class '__main__.B'>,
 '__builtins__': <module 'builtins' (built-in)>, '__spec__': None}

[Newlines added for legibility]

Running same code in a module (as opposed to interpreter) results in the exact same behavior. Using Anaconda's Python 3.5.1 :: Continuum Analytics, Inc..


Solution

  • It's ugly but You could access globals:

    __a = 3
    class B:
        def __init__(self):
            self.a = globals()["__a"]
    b = B()
    

    You can also put it in a dict:

    __a = 3
    
    d = {"__a": __a}
    
    class B:
        def __init__(self):
            self.a = d["__a"]
    b = B()
    

    Or a list, tuple etc.. and index:

    __a = 3
    
    l = [__a]
    
    class B:
        def __init__(self):
            self.a = l[0]
    b = B()