gpt4 book ai didi

Python 名称修改允许双向访问

转载 作者:行者123 更新时间:2023-12-05 04:36:26 24 4
gpt4 key购买 nike

所以我遇到了一个非常有趣的 python 名称修改行为。考虑以下代码

class C:
def __init__(self):
self.__c = 1

@staticmethod
def change(instance):
print(dir(instance))
print(instance.__c)
print(instance._C__c)

在这里,我创建了一个私有(private)字段 __c 并希望从类内直接访问它,并从类外通过 _C__c 访问它。因此,如果我们将 C 的一个实例传递给 C.change,则第二次或第三次打印都应该失败。
让我们检查一下:


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

首先,为了调试,我们使用 dir(c) 打印所有可用的 c 成员。然后我们调用 C.change 将变量 c 传递给它。
嗯,出乎意料,没有错误。
因此,首先在 change 中打印向我们展示了 instance 对象的所有可用条目。在这里我们看到字段 __c 可用作 _C__c。这似乎没问题,因为我们不是通过自身访问,而是通过另一个变量访问。
从“dir”获得这样的输出,我希望 print(instance.__c) 因 AttributeError 而失败。
然而,没想到,它运行得很好!
这真的让我感到困惑,因为我不明白,为什么 __c 是可访问的,如果它是设计的,那么为什么它没有列在 dir 输出中?

最佳答案

每当你写__c在一个类中,它将被文本替换为 _<classname>__c .它不是动态执行的,它是在解析阶段完成的。因此,解释器永远不会看到 __c , 只有 _<classname>__c .这就是为什么只有 _C__c出现在 dir(instance) .

引用 the docs :

[...] 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. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used. [...]

因此,它仅适用于点属性访问 ( x.y ),不适用于通过 (get|set)attr 进行的动态访问:

>>> class Foo:
... def __init__(self):
... setattr(self, '__x', 'test')
...
>>> Foo().__x
'test'

关于Python 名称修改允许双向访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70849402/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com