【问题标题】:How to access "__" (double underscore) variables in methods added to a class如何在添加到类的方法中访问“__”(双下划线)变量
【发布时间】:2017-10-22 05:04:24
【问题描述】:

背景

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

【问题讨论】:

标签: python class metaprogramming


【解决方案1】:
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())

【讨论】:

  • 能否请您添加一些解释,说明为什么这可以解决原始发帖人的问题。
【解决方案2】:

回答你的两个问题:

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

  1. Python documentation:

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

让我为你打破它,它的意思是当你的解释器遇到一个名字错位的名字时,它在哪里阅读并不重要。 只有在它出现在类的定义中时,该名称才会被破坏,而在你的情况下,它不是。因为它不是直接“在”类定义下。因此,当它读取 self.__cat 时,它会将其保留在 self.__cat将在文本上将其替换为 self._Test__cat,因为它没有在 Test 类中定义。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 在这个 Django docs.djangoproject.com/en/2.0/intro/tutorial02 的文档教程中。有这个代码行' Question.objects.get(pub_date__year=current_year)' 并且 pub date year var 有一个双下划线,这和你提到的一样吗?@Blckknght
    • @LordDraagon:不,这似乎是 Django 自己的事情。它的拼写可能部分受到 Python 原生名称 mangling 的启发,但它是单独实现的,并且具有不同的含义。我认为双下划线有点像属性符号中的点(所以pub_date__year有点像pub_date.year)。我对 Django 的了解还不够,无法给出更完整的解释。
    【解决方案4】:

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

    Python doc了解更多信息

    【讨论】:

    • 我想到了这一点,但是由于我将newmethod2 添加为方法,因此我认为行为应该是相同的。即我可以访问self.__cat
    猜你喜欢
    • 2011-10-19
    • 1970-01-01
    • 2019-06-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    相关资源
    最近更新 更多