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

时间:2017-05-22 13:46:36

标签: python class metaprogramming

背景

我希望使用元类来添加基于原始类的辅助方法。如果我想要添加的方法使用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'

问题

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

(不将self.__cat重命名为self._cat。)

也许更基本的一点,为什么self.__cat对于这两种情况都不会以同样的方式对待,因为newfunction2现在是Test的一部分?

4 个答案:

答案 0 :(得分:6)

当编译类中的方法时,会发生名称重整。像__foo这样的属性名称被转换为_ClassName__foo,其中ClassName是定义方法的类的名称。请注意,您可以对其他对象的属性使用名称修改! / p>

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

确实,防止在您的类中定义的代码访问您的属性是使用名称修改的全部原因。通常,如果您正在编写代理或mixin类型,并且您不希望您的内部使用属性与您正在代理或混入的类的属性(您不会知道)发生冲突,那么它是值得打扰的。提前)。

答案 1 :(得分:1)

回答你的两个问题:

  1. 由于名称修改规则,您需要在self.__catnewfunction2之后更改self._Test__cat
    1. Python documentation:
    2.   

      这种破坏是在不考虑句法位置的情况下完成的   标识符,只要它出现在类的定义中。

      让我为你制造它,它说当你的翻译遇到一个名字错误的名字时读取的地方并不重要。 如果它出现在类的定义中,那么该名称只会被损坏,在您的情况下,它不是。因为它不直接"在"一个类定义。因此,当它显示为self.__cat时,它会将其保持在self.__cat将文本替换为self._Test__cat,因为它不是{\ n}在Test类中定义。

答案 2 :(得分:0)

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

Python doc

中了解详情

答案 3 :(得分:0)

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