Python “如何访问”__&引用;(双下划线)添加到类的方法中的变量 背景

Python “如何访问”__&引用;(双下划线)添加到类的方法中的变量 背景,python,class,metaprogramming,Python,Class,Metaprogramming,我希望使用一个元类,以便在原始类的基础上添加助手方法。如果我想添加的方法使用了self.\uu attributeName我会得到一个AttributeError(因为名称混乱),但对于现有的相同方法,这不是问题 代码示例 下面是一个简化的例子 # Function to be added as a method of Test def newfunction2(self): """Function identical to newfunction""" print self.m

我希望使用一个元类,以便在原始类的基础上添加助手方法。如果我想添加的方法使用了
self.\uu 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.\uu cat

(无需将
self.\uu cat
重命名为
self.\u cat

也许还有更基本的问题,为什么这两种情况下,
self.\uu cat
的处理方式不一样,因为
newfunction2
现在是
Test
的一部分?

您可以使用
\u Test\uu cat
Test
类访问
\uu cat
属性。(其中,
替换为
self
测试
类的任何其他实例)


中了解更多信息以回答您的两个问题:

  • 当您需要将其从
    newfunction2
    调用为
    self.\u Test\u cat
    时,您需要将其更改为
    self.\u cat
    ,这要归功于名称损坏规则
  • 这种破坏是在不考虑语法位置的情况下进行的 标识符,只要它出现在类的定义中


    让我帮你把它打断,意思是当你的解释器遇到一个被弄坏的名字时,它在哪里阅读并不重要仅当名称出现在类的定义中时,名称才会被损坏,而在您的情况下,它不是。因为它不是直接“在”类定义之下。因此,当它读取
    self.\uuuuu cat
    时,它将其保持在
    self.\uuu cat
    不会将其文本替换为
    self.\utest\uu cat
    ,因为它不是在
    Test
    类中定义的。

    编译类中的方法时会发生名称损坏。像
    \uuuuufoo
    这样的属性名会被转入
    \u ClassName\uuuuuufoo
    ,其中
    ClassName
    是定义方法的类的名称。请注意,您可以对其他对象的属性使用名称混乱

    在您的代码中,
    newfunction2
    中的名称不起作用,因为编译函数时,它不是类的一部分。因此,
    \uuuuuCAT
    的查找不会像在
    测试中那样变成
    \uuuuTEST\uCAT
    。如果愿意,您可以显式查找属性名称的损坏版本,但听起来您希望
    newfunction2
    是泛型的,并且可以添加到多个类中。不幸的是,这不适用于名称损坏


    实际上,防止类中未定义的代码访问属性是使用名称篡改的全部原因。通常,只有在编写代理或mixin类型并且不希望内部使用属性与代理或混合的类的属性发生冲突(您事先不知道)的情况下,才值得考虑这个问题。

    我想到了这一点,但由于我将
    newmethod2
    添加为一个方法,我认为行为应该是一样的。i、 e.我可以访问的
    self.\uu cat
    。相关:Django的本文档教程中可能存在的副本。代码行'Question.objects.get(pub_date_year=current_year')和pub date year变量有一个双下划线,这与您提到的相同吗@Blckknght@LordDraagon:不,那似乎是Django自己的事。它的拼写可能部分受到Python的本地名称mangling的启发,但它是单独实现的,具有不同的含义。我认为双下划线有点像属性符号中的点(因此
    pub\u date\u year
    有点像
    pub\u date.year
    )。我对Django了解不够,无法给出更完整的解释。请您补充一些解释,解释为什么这可以解决原始海报的问题。
    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())