使用SQL Alchemy声明性基础处理元类冲突

时间:2010-09-02 11:25:18

标签: python sqlalchemy metaclass

我有一个class X,它派生自一个拥有自己的元类Meta的类。我还希望从SQL Alchemy中的声明性基础派生X.但我不能做那么简单的

def class MyBase(metaclass = Meta):
    #...

def class X(declarative_base(), MyBase):
    #...

因为我会得到元类冲突错误:'派生类的元类必须是其所有基础的元类的(非严格)子类。我知道我需要创建一个新的元类,它可以从Meta和声明性基础使用的任何元类派生(我认为DeclarativeMeta?)。所以写下来就足够了:

def class NewMeta(Meta, DeclarativeMeta): pass
def class MyBase(metaclass = NewMeta):
    #...
def class X(declarative_base(), MyBase):
    #...

我尝试了这个,似乎工作;但是我担心这个代码可能会引入一些问题。

我阅读了手册,但对我来说有点太神秘了。什么是

修改

我的课程所用的代码如下:

class IterRegistry(type):
    def __new__(cls, name, bases, attr):
        attr['_registry'] = {}
        attr['_frozen'] = False
        print(name, bases)
        print(type(cls))
        return type.__new__(cls, name, bases, attr)
    def __iter__(cls):
        return iter(cls._registry.values())

class SQLEnumMeta(IterRegistry, DeclarativeMeta): pass  

class EnumType(metaclass = IterRegistry):
    def __init__(self, token):
        if hasattr(self, 'token'):
            return
        self.token = token
        self.id = len(type(self)._registry)
        type(self)._registry[token] = self

    def __new__(cls, token):
        if token in cls._registry:
            return cls._registry[token]
        else:
            if cls._frozen:
                raise TypeError('No more instances allowed')
            else:
                return object.__new__(cls)

    @classmethod
    def freeze(cls):
        cls._frozen = True

    def __repr__(self):
        return self.token

    @classmethod
    def instance(cls, token):
        return cls._registry[token]

class C1(Base, EnumType, metaclass = SQLEnumMeta):
    __tablename__ = 'c1'
    #...

1 个答案:

答案 0 :(得分:3)

修改:现在看了IterRegistryDeclarativeMeta,我觉得你的代码还可以。

IterRegistry定义__new____iter__,而DeclarativeMeta定义__init____setattr__。由于没有重叠,因此无需直接调用super。不过,最好这样做,以便为将来的代码提供证据。


您是否可以控制Meta的定义?你能告诉我们它的定义吗?除非我们看到Meta的定义,否则我认为我们不能说它有效或无效。

例如,如果您的Meta未致电,则可能存在问题 super(Meta,cls).__init__(classname, bases, dict_)

如果您运行此代码

class DeclarativeMeta(type):
    def __init__(cls, classname, bases, dict_):
        print('DeclarativeMeta')
        # if '_decl_class_registry' in cls.__dict__:
        #     return type.__init__(cls, classname, bases, dict_)       
        # _as_declarative(cls, classname, dict_)
        return type.__init__(cls, classname, bases, dict_)

class Meta(type):
    def __init__(cls, classname, bases, dict_):
        print('Meta')
        return type.__init__(cls, classname, bases, dict_)

class NewMeta(Meta,DeclarativeMeta): pass

class MyBase(object):
    __metaclass__ = NewMeta
    pass

然后只打印字符串'Meta'。 换句话说,只有Meta.__init__才能运行。 DeclarativeMeta.__init__被跳过。

另一方面,如果你定义

class Meta(type):
    def __init__(cls, classname, bases, dict_):
        print('Meta')
        return super(Meta,cls).__init__(classname, bases, dict_)

然后Meta.__init__DeclarativeMeta.__init__都会运行。