Python __super 黑魔法失败了

Posted

技术标签:

【中文标题】Python __super 黑魔法失败了【英文标题】:Python __super black magic failed 【发布时间】:2016-12-05 01:55:20 【问题描述】:

我想为元类创建的每个类添加一个属性。例如,当创建一个名为C 的类时,我想添加一个属性C._C__sup,其值为描述符super(C)

这是我尝试过的:

class Meta(type):
    def __init__(cls, name, bases, dict): # Not overriding type.__new__
        cls.__dict__['_' + name + '__sup'] = super(cls)
        # Not calling type.__init__; do I need it?

class C(object):
    __metaclass__ = Meta

c = C()
print c._C__sup

这给了我:

TypeError: Error when calling the metaclass bases
    'dictproxy' object does not support item assignment

一些背景资料:(您不必阅读这部分)

受this article 的启发,我正在做的是在使用super 时避免“硬编码”类名:

这里的想法是将未绑定的超级对象用作私有对象 属性。例如,在我们的示例中,我们可以定义私有 属性__sup 在类C 中作为未绑定的超级对象 super(C):

>>> C._C__sup = super(C)

在方法中使用此定义,语法self.__sup.meth 可以用作super(C, self).meth 的替代品。优势 是你避免在调用中重复类名 语法,因为该名称隐藏在 private 的修饰机制中 名字。 __sup属性的创建可以隐藏在一个 元类并自动生成。所以,这一切似乎都有效:但是 其实不是这样的。

【问题讨论】:

【参考方案1】:

使用setattr 而不是分配给cls.__dict__

class Meta(type):
    def __init__(cls, name, bases, clsdict): # Not overriding type.__new__
        setattr(cls, '_' + name + '__sup', super(cls))
        super(Meta, cls).__init__(name, bases, clsdict)

class C(object):
    __metaclass__ = Meta
    def say(self):
        return 'wow'

class D(C):
    def say(self):
        return 'bow' + self.__sup.say()

c = C()
print(c._C__sup)
# <super: <class 'C'>, <C object>>
d = D()
print(d.say())

打印

bowwow

顺便说一句,打个电话是个好主意

        super(Meta, cls).__init__(name, bases, clsdict)

Meta.__init__ 中允许Meta 参与到类层次结构中 可能需要super 才能正确调用__init__s 链。这似乎 特别合适,因为您正在构建一个元类来协助 使用super

【讨论】:

以上是关于Python __super 黑魔法失败了的主要内容,如果未能解决你的问题,请参考以下文章

python 黑魔法收集

Python的黑魔法@property装饰器的使用技巧

Python3 魔法方法:算数运算

黑魔法__attribute__((cleanup))

黑魔法__attribute__((cleanup))

黑魔法来了,不要眨眼