有没有一种方法可以在类定义之后设置元类? [英] Is there a way to set metaclass after the class definition?

查看:54
本文介绍了有没有一种方法可以在类定义之后设置元类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了设置类的元类,我们使用__metaclass__属性.元类是在定义类时使用的,因此在类定义之后显式设置它无效.

In order to set metaclass of a class, we use the __metaclass__ attribute. Metaclasses are used at the time the class is defined, so setting it explicitly after the class definition has no effect.

当我尝试显式设置元类时,会发生这种情况;

This is what happens when I try to set metaclasses explicitly;

>>> class MetaClass(type):
    def __new__(cls, name, bases, dct):
        dct["test_var"]=True
        return type.__new__(cls, name, bases, dct)
    def __init__(cls, name, bases, dct):
        super(MetaClass, cls).__init__(name, bases, dct)


>>> class A:
    __metaclass__=MetaClass


>>> A.test_var
True
>>> class B:
    pass

>>> B.__metaclass__=MetaClass
>>> B.test_var

Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    B.test_var
AttributeError: class B has no attribute 'test_var'

我能想到的最好的主意是重新定义整个类并以某种方式动态添加__metaclass__属性.或者您知道在类定义之后设置元类的更好方法吗?

The best idea I can think of is to re-define whole class and add the __metaclass__ attribute dynamically somehow. Or do you know a better way set metaclass after the class definition?

推荐答案

创建类后,可以像更改对象的类一样更改元类,但是会遇到很多问题.对于初学者,初始元类必须与type不同,新元类的__init____new__不会被调用(尽管您可以手动调用__init__或执行__init__的方法"的工作).

You can change the metaclass after class creation the same way that you can change the class of an object, however you'd have a lot of issues. For starters, the initial metaclass needs to be different from type, the __init__ and __new__ of the new metaclass won't be called (though you can manually call __init__ or a method that performs __init__'s job).

更改元类的最麻烦的方法可能是从头开始重新创建该类:

Possibly the least troublesome way to change the metaclass is to recreate the class again from scratch:

B = MetaClass(B.__name__, B.__bases__, B.__dict__)

但是,如果您坚持动态更改元类,则首先需要使用临时自定义元类定义B:

But if you insist on changing the metaclass dynamically, you first need to define B with a temporary custom metaclass:

class _TempMetaclass(type):
    pass

class B:
    __metaclass__ = _TempMetaclass # or: type('temp', (type, ), {})

然后您可以像这样定义元类:

Then you can define the metaclass like that:

class MetaClass(type):
    def __init__(cls, *a, **kw):
        super(MetaClass, cls).__init__(*a, **kw)
        cls._actual_init(*a, **kw)
    def _actual_init(cls, *a, **kw):
        # actual initialization goes here

然后执行以下操作:

B.__class__ = MetaClass
MetaClass._actual_init(B, B.__name__, B.__bases__, B.__dict__)

您还需要确保该类的所有初始化均已完成_actual_init.您还可以在元类中添加classmethod,从而为您更改元类.

You also need to make sure that all the initialization of the class is done _actual_init. You can also add a classmethod to the metaclass that changes the metaclass for you.

这两种解决方案都有一个缺点,即B的基数会受到限制-它们必须与原始和新的元类都兼容,但是我想这对您来说不是问题.

Both solutions have the slight shortcoming that B's bases would be limited - they need to be compatible with both the original and the new metaclass, but I guess that's not an issue in your case.

这篇关于有没有一种方法可以在类定义之后设置元类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆