[英]Python name mangling allows access both ways
So I have come across a very interesting behavior of python name mangling.所以我遇到了一个非常有趣的 python 名称修改行为。 Consider the following code
考虑以下代码
class C:
def __init__(self):
self.__c = 1
@staticmethod
def change(instance):
print(dir(instance))
print(instance.__c)
print(instance._C__c)
Here I create a private field __c and expect to have direct access to it from within class and access via _C__c from outside of the class.在这里,我创建了一个私有字段 __c 并希望可以从 class 内部直接访问它,并从 class 外部通过 _C__c 访问它。 So, if we pass an instance of C to C.change either 2nd or 3rd print should fail.
因此,如果我们将 C 的实例传递给 C。更改第二次或第三次打印都应该失败。
Lets check:让我们检查:
>>> c = C()
>>> dir(c)
['_C__c', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'change']
>>> C.change(c)
['_C__c', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'change']
1
1
First, for debug we print all available members of c with dir(c)
.首先,为了调试,我们使用
dir(c)
打印 c 的所有可用成员。 Then we call C.change passing it the variable c
.然后我们调用 C.change 传递变量
c
。
Hmm, that is unexpected, no errors.嗯,这是意料之外的,没有错误。
So, first print in change
shows us all the available entries of the instance
object.因此,第一个 print in
change
向我们展示了instance
object 的所有可用条目。 Here we see that field __c
is available as _C__c
.在这里,我们看到字段
__c
可用作_C__c
。 That seems ok, since we access not through self, but through another variable.这似乎没问题,因为我们不是通过自我访问,而是通过另一个变量。
Having such output from 'dir' I expect print(instance.__c)
to fail with AttributeError.从“dir”获得这样的 output 我希望
print(instance.__c)
会因 AttributeError 而失败。
However, unexpectedly, it works just fine!然而,出乎意料的是,它工作得很好!
This really confuses me, since I do not understand, why is __c
accessible and if it is so by design, then why is it not listed in dir
output?这真的让我很困惑,因为我不明白,为什么
__c
可以访问,如果是这样设计的,那么为什么它没有在dir
output 中列出?
Whenever you write __c
inside a class, it will be textually replaced by _<classname>__c
.每当您在 class 中写入
__c
时,它将在文本上被_<classname>__c
替换。 It's not dynamically performed, it's done at the parsing stage.它不是动态执行的,它是在解析阶段完成的。 Hence, the interpreter won't ever see
__c
, only _<classname>__c
.因此,解释器永远不会看到
__c
,只会看到_<classname>__c
。 That's why only _C__c
appears in dir(instance)
.这就是为什么只有
_C__c
出现在dir(instance)
中。
[...] Private names are transformed to a longer form before code is generated for them.
[...] 在为其生成代码之前,私有名称会被转换为更长的形式。 The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name.
转换插入 class 名称,在名称前面删除了前导下划线并插入了一个下划线。 For example, the identifier
__spam
occurring in a class namedHam
will be transformed to_Ham__spam
.例如,出现在名为
Ham
的 class 中的标识符__spam
将转换为_Ham__spam
。 This transformation is independent of the syntactical context in which the identifier is used.此转换与使用标识符的语法上下文无关。 [...]
[...]
For that reason, it only applies to dotted attribute access ( xy
), not to dynamic access via (get|set)attr
:因此,它仅适用于点属性访问 (
xy
),不适用于通过(get|set)attr
进行的动态访问:
>>> class Foo:
... def __init__(self):
... setattr(self, '__x', 'test')
...
>>> Foo().__x
'test'
__
-prefixed names work fine as-is inside the class's own methods. __
前缀名称在类自己的方法中可以正常工作。 It's only outside the class (including in its subclasses) that the modified name is needed to access the attribute, due to name-mangling .由于name-mangling ,只有在class (包括在其子类中)之外,才需要修改后的名称才能访问该属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.