In Python 3, prefixing a class variable makes it private my 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.
.
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()
Apparently the "official" answer is not to use double underscores outside of a class. This is implied in the documentation here: https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references. Furthermore, the following (failed) bug report (and this response) make it explicit.
You are instantiating a class by passing a variable which is not defined. putting __a outside the class will not not work as the class will not see this variable. What you should do instead is:
__a = 3
class B:
def __init__(self, __a):
self.a = __a
b = B(__a)
This way you would have passed an argument in the constructor for initializing.
If you are going to mangle the names as you are trying to do then I would refer you to this article: http://shahriar.svbtle.com/underscores-in-python
As such, my solution to what you are trying to do is as follows:`
class R:
global _R__a
_R__a = 3
def __init__(self):
pass
class B:
global _R__a
def __init__(self):
self.a = _R__a
b = B()
print b.a
#3`
This way, you are also more specific about the variable you are calling without much room for modifying it later. Hope this works.