Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python私有属性名称混乱继承_Python_Inheritance_Private - Fatal编程技术网

python私有属性名称混乱继承

python私有属性名称混乱继承,python,inheritance,private,Python,Inheritance,Private,这是“高效Python”中的一个例子,我显然遗漏了一些东西。我添加了一些印刷品来帮助说服自己,但我还是有点不清楚 我知道,当您尝试访问继承的私有变量时,它会失败,因为在子对象的实例字典中,名称已损坏(下面最后一行,尝试访问a.。\uu值理所当然地会失败,因为实例dict包含损坏的版本\u ApiClass\uu值) 我被绊倒的地方是为什么继承的方法get没有这个问题。如果您在调用get时打印self.\uuuu dict\uuuu,您可以看到我们仍在使用相同的子实例dict,就像我们试图直接从子

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

我知道,当您尝试访问继承的私有变量时,它会失败,因为在子对象的实例字典中,名称已损坏(下面最后一行,尝试访问
a.。\uu值
理所当然地会失败,因为实例dict包含损坏的版本
\u ApiClass\uu值

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

我对属性访问的理解是,在封面下,本质上发生的事情(尽管是简化的)是
a.\uu值
基本上是
a.\uu dict\uu[''.\uu值']
。这是有道理的,当您试图直接访问继承的私有变量时,它就被证明了,因为它失败了,因为只有损坏的名称在子dict中。然而,继承的方法
get
,它在来自子dict的同一个实例dict上操作,使用点访问,因此它显然没有执行
a.。uuu dict_uuuu[''uuu值']
,而是
a.uu dict_uu['''u ApiClass_uvalue']

这里的区别是什么,使得
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
,而
ApiClass
get
被损坏,无法使用
ApiClass

这是故意的。这里的目标是,在类
X
中定义的方法会对
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\u ATTR
值,
\u Parent\uuuuu x
已硬编码到字节码中

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


其中,
加载属性
只是尝试加载普通的
\uuux
名称,而不是损坏的版本;如果
bar
是一个类的实例,那么由于名称损坏保护,这不太可能起作用。

名称损坏是在字节码编译时完成的,因此名称损坏取决于函数的定义位置,而不是它的调用方式
Child
没有自己的
get
方法,它使用的是
ApiClass
,而
ApiClass
get
被损坏,无法使用
ApiClass

这是故意的。这里的目标是,在类
X
中定义的方法会对
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\u ATTR
值,
\u Parent\uuuuu x
已硬编码到字节码中

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


其中,
加载属性
只是尝试加载普通的
\uuux
名称,而不是损坏的版本;如果
bar
是一个类的实例,由于名称损坏保护,这很可能不起作用。

您的
ApiClass.get()
的第二行上的注释表明该行不起作用,但没有问题。除了在最后一行尝试访问
a.\uu值
之外,我可以运行此代码,没有任何错误。文档中清楚地解释了损坏规则:@Craig-修复了第二行的打字错误,对此表示抱歉。也就是说,让我参考文档并不是特别有帮助。您的
ApiClass.get()
的第二行上的注释表明该行不起作用,但很好。除了在最后一行尝试访问
a.\uu值
之外,我可以运行此代码,没有任何错误。文档中清楚地解释了损坏规则:@Craig-修复了第二行的打字错误,对此表示抱歉。也就是说,让我参考这些文件并没有特别大的帮助。