如何在添加到类的方法中访问"__"(双下划线)变量



Background

我希望使用元类来添加基于原始类的辅助方法。如果我想添加的方法使用self.__attributeName我得到了一个AttributeError(因为名称重整),但对于现有的相同方法,这不是问题。

代码示例

这是一个简化的示例

# Function to be added as a method of Test
def newfunction2(self):
"""Function identical to newfunction"""
print self.mouse
print self._dog
print self.__cat
class MetaTest(type):
"""Metaclass to process the original class and
add new methods based on the original class
"""
def __new__(meta, name, base, dct):
newclass = super(MetaTest, meta).__new__(
meta, name, base, dct
)
# Condition for adding newfunction2
if "newfunction" in dct:
print "Found newfunction!"
print "Add newfunction2!"
setattr(newclass, "newfunction2", newfunction2)
return newclass
# Class to be modified by MetaTest
class Test(object):
__metaclass__ = MetaTest
def __init__(self):
self.__cat = "cat"
self._dog = "dog"
self.mouse = "mouse"
def newfunction(self):
"""Function identical to newfunction2"""
print self.mouse
print self._dog
print self.__cat
T = Test()
T.newfunction()
T.newfunction2() # AttributeError: 'Test' object has no attribute '__cat'

问题

有没有办法添加可以使用self.__catnewfunction2

(无需将self.__cat重命名为self._cat

也许更基本的事情是,既然newfunction2现在是Test的一部分,为什么self.__cat对这两种情况都不以相同的方式对待?

编译类中的方法时会发生名称重整。属性名称(如__foo)被转入_ClassName__foo,其中ClassName是定义方法的类的名称。请注意,您可以对其他对象的属性使用名称重整!

在您的代码中,newfunction2中的名称重整不起作用,因为在编译函数时,它不是类的一部分。因此,__cat的查找不会像在Test.__init__中那样变成__Test_cat。如果需要,您可以显式查找属性名称的损坏版本,但听起来您希望newfunction2是通用的,并且能够添加到多个类中。不幸的是,这不适用于名称重整。

实际上,防止类中未定义的代码访问属性是使用名称重整的全部原因。通常,只有当您正在编写代理或 mixin 类型并且不希望您的内部使用属性与您代理或混合的类的属性发生冲突(您事先不会知道)时,才值得打扰。

要回答您的两个问题:

  1. 由于名称重整规则,当您需要将其从newfunction2调用到self._Test__cat时,您需要更改self.__cat

  1. Python 文档:

这种重整是在不考虑 标识符,只要它出现在类的定义中。

让我为你刹车,它说当你的口译员遇到一个名字被篡改的名字时,它在哪里阅读并不重要。仅当名称出现在类的定义中时,该名称才会被破坏,而在您的情况下,它不是。因为它不直接"在"类定义下。所以当它读取self.__cat时,它保持self.__cat而不是self._Test__cat文本替换它,因为它不是在Test类中定义的。

您可以使用<Test instance>._Test__catTest类访问__cat属性。 (其中<Test instance>selfTest类的任何其他实例替换)

在 Python 文档中了解更多信息

class B:
def __init__(self):
self.__private = 0 
def __private_method(self):
'''A private method via inheritance'''
return ('{!r}'.format(self))
def internal_method(self):
return ('{!s}'.format(self))
class C(B):
def __init__(self):
super().__init__()
self.__private = 1
def __private_method(self):
return 'Am from class C'
c = C()
print(c.__dict__)
b = B()
print(b.__dict__)
print(b._B__private)
print(c._C__private_method())

最新更新