How to access private variable of Python module fr

2019-08-14 11:06发布

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..

4条回答
Root(大扎)
2楼-- · 2019-08-14 11:21

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.

查看更多
来,给爷笑一个
3楼-- · 2019-08-14 11:23

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.

查看更多
爷、活的狠高调
4楼-- · 2019-08-14 11:25

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()
查看更多
祖国的老花朵
5楼-- · 2019-08-14 11:33

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.

查看更多
登录 后发表回答