python私有属性名称重整继承

太阳神

这是“Effective Python”中的一个例子,我显然遗漏了一些东西。我添加了一些印刷品以帮助说服自己,但我仍然有点不清楚。

我知道当您尝试访问继承的私有变量时,它会失败,因为在子项的实例字典中,名称已被损坏(下面的最后一行,尝试正确访问a.__value失败,因为实例 dict 包含损坏的版本_ApiClass__value)。

我被绊倒的地方是为什么继承的方法get没有这个问题。如果您self.__dict__在对 的调用中打印get,您可以看到我们仍在使用相同的 Child 实例字典,就像我们尝试直接从子对象(仅包含损坏的名称)使用点访问一样。此方法中的点属性访问以某种方式正确转换为损坏的名称并检索私有变量。

我对属性访问的理解是,在幕后,本质上发生的事情(尽管简化了)a.__value基本上是a.__dict__['__value']. 这是有道理的,并在您尝试直接访问继承的私有变量时得到了证明,因为它失败了,因为在Child dict中只有错误的名称。然而get,在 Child 的同一个实例 dict 上运行的继承方法使用点访问,所以它显然不是在做a.__dict__['__value'],而是在a.__dict__['_ApiClass__value'].

get与来自子级的类似属性访问相比,这里有什么区别导致方法内的私有属性访问知道损坏的名称?

class ApiClass():
    def __init__(self):
        self.__value = 5

    def get(self):
        print(self.__dict__['_ApiClass__value']) #succeeds
        print(self.__dict['__value']) #fails bc name mangle
        return self.__value #how is this translated to '_ApiClass_value'
                            #but a similar instance lookup fails?

class Child(ApiClass):
    def __init__(self):
        super().__init__()
        self._value = 'hello'

a = Child()
print(a.__dict__)
print(a.get())   #works, but instance dict has no '__value' key? 
print(a.__value) #fail bc name mangled to '_ApiClass_value'
暗影游侠

名称修改是在字节码编译时完成的,因此名称修改取决于函数的定义位置,而不是通过什么调用它。Child没有自己的get方法,它使用ApiClass's,并且ApiClass'sget被破坏以与ApiClass.

这是故意的。这里的目标是在类Xmangle 中定义的方法,X无论您如何到达它们。如果他们没有,并且父母和孩子都定义了一个具有相同名称的私有变量,则父母将无法私有访问其自己唯一版本的变量,它将与孩子共享(即使在每种情况下,变量的含义可能完全不同)。

dis模块可以证明修改是在编译时的事实:

class Parent:
    def x(self):
        return self.__x

class Child(Parent):
    pass

然后交互式检查:

>>> import dis
>>> dis.dis(Parent.x)
  3           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (_Parent__x)
              6 RETURN_VALUE
>>> dis.dis(Child.x):
  3           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (_Parent__x)
              6 RETURN_VALUE

请注意,该LOAD_ATTR_Parent__x被硬编码到字节码中。

您还可以演示如何在普通函数中不涉及特殊行为(与定义为类的一部分的方法相反):

>>> def foo(bar): return bar.__x
>>> dis.dis(foo)
  1           0 LOAD_FAST                0 (bar)
              3 LOAD_ATTR                0 (__x)
              6 RETURN_VALUE

其中LOAD_ATTR只是试图加载普通__x的名字,而不是错位的版本; 如果bar是一个类的实例,由于名称修改保护,这极不可能起作用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

私有属性被继承

来自分类Dev

假设我不使用任何重载函数,是否有办法可以停止所有名称重整?

来自分类Dev

使用私有继承的合格名称的行为

来自分类Dev

有关“私有”属性和python中的继承的问题

来自分类Dev

Objective-C:继承受保护/私有原子属性

来自分类Dev

继承的私有函数

来自分类Dev

私有变量继承

来自分类Dev

继承的私有函数

来自分类常见问题

Python中私有和受保护方法的继承

来自分类Dev

在python属性后面访问“私有”变量

来自分类Dev

根据模板的类型名称设置私有属性

来自分类Dev

按名称重用python中的方法

来自分类Dev

继承和私有变量

来自分类Dev

C ++私有类继承

来自分类Dev

.Net Xml序列化器使用私有属性名称而不是公共属性名称

来自分类Dev

从具有相同名称的属性的接口继承

来自分类Dev

EF迁移时属性名称重复错误

来自分类Dev

EF迁移时属性名称重复错误

来自分类Dev

如何从Xamarin Forms中的另一个ContentPage访问/继承私有字段属性?

来自分类Dev

导出接口的属性“ <properyName>”具有或正在使用私有名称“ <name>”

来自分类Dev

私有继承与公开迭代器

来自分类Dev

Java继承中的私有方法

来自分类Dev

私有继承和隐式转换

来自分类Dev

友谊和私有嵌套类的继承

来自分类Dev

私有继承和虚拟功能

来自分类Dev

Java继承中的私有方法

来自分类Dev

Javascript继承,子类自己的私有变量

来自分类Dev

Java中的继承和私有变量

来自分类Dev

继承私有结构C ++的公共结构