【问题标题】:How to stack metaclasses如何堆叠元类
【发布时间】:2018-06-05 19:59:48
【问题描述】:

我想“堆叠”元类。

def dec(cls):
    class newmeta(cls.__metaclass__):
        def __call__(cls, *args, **kwargs):
            obj = cls.__metaclass__.__call__(cls, *args, **kwargs)
            obj.x *= 2 #this happens AFTER __init__ is called
    cls.__metaclass__ = newmeta
    return cls

@dec
@dec
class Foo(object):
    def __init__(self, x):
        self.x = 5

print Foo().x #expect 20

但是,我似乎无法以这种方式访问​​Foo.__metaclass__....实际上是("__metaclass__" in Foo.__dict__) == False

如何解决这个问题?

【问题讨论】:

  • 您实际上想用这个实现什么?你读过例如stackoverflow.com/q/5120688/3001761?
  • 目标是在调用__init__方法后执行一系列事件。我可能只是用 mixins 来解决它,然后在最后调用一堆超级。
  • “元类是比 99% 的用户所担心的更深层次的魔法。”如果有一种方法可以在不使用它们的情况下完成你想要的,那就去做吧。

标签: python python-2.x metaclass


【解决方案1】:

更改现有的cls.__metaclass__ 无效,因为元类决定了类的构建方式,您必须使用您的元类创建一个新的类对象:

def dec(cls):
    basetype = type(cls)
    class newmeta(basetype):
        def __call__(cls, *args, **kwargs):
            obj = super(newmeta, cls).__call__(*args, **kwargs)
            obj.x *= 2
            return obj
    new_cls = newmeta(cls.__name__, cls.__bases__, dict(cls.__dict__))
    return new_cls


@dec
@dec
class Bar(object):

    def __init__(self):
        self.x = 5


o = Bar()
print o.x

产量:

20

ps:此方法适用于 python 2 和 3。

【讨论】:

    【解决方案2】:

    如果您谈论的是 Python 3.5+,则不再支持 __metaclass__,如此处所述 __metaclass__ in Python3.5

    【讨论】:

      猜你喜欢
      • 2020-09-15
      • 2018-11-26
      • 1970-01-01
      • 2010-11-18
      • 2013-01-21
      • 1970-01-01
      • 1970-01-01
      • 2021-09-21
      • 1970-01-01
      相关资源
      最近更新 更多