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

Hay*_*don 9 python metaprogramming class

背景

我希望使用元类来添加基于原始类的辅助方法.如果我希望添加的方法使用,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'
Run Code Online (Sandbox Code Playgroud)

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

(不重命名self.__catself._cat.)

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

Blc*_*ght 9

名称编译是在编译类中的方法时发生的。像这样的属性名称__foo都被转换为_ClassName__foo,其中,ClassName是在其中定义该方法的类的名称。请注意,您可以对其他对象的属性使用名称修饰!

在您的代码中,mangling in名称newfunction2不起作用,因为在编译函数时,该名称不属于该类。因此,对的查询__cat不会变成__Test_cat它们的处理方式Test.__init__。您可以根据需要显式查找属性名称的变形版本,但这听起来像是newfunction2通用的,并且可以添加到多个类中。不幸的是,这不适用于名称修饰。

确实,防止在类中未定义的代码访问属性是使用名称修饰的全部原因。通常,只有在编写代理或混合类型并且不希望内部使用属性与您要代理或混合的类的属性相冲突时,才值得打扰(您不会知道提前)。