处理与 SQL Alchemy 声明基的元类冲突

发布于 2024-09-16 20:37:56 字数 1844 浏览 0 评论 0原文

我有一个 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'
    #...

I have a class X which derives from a class with its own metaclass Meta. I want to also derive X from the declarative base in SQL Alchemy. But I can't do the simple

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

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

since I would get metaclass conflict error: 'the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases'. I understand that I need to create a new metaclass that would derive from both Meta and from whatever metaclass the declarative base uses (DeclarativeMeta I think?). So is it enough to write:

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

I tried this, and it seems to work; but I'm afraid I may have introduced some problem with this code.

I read the manual, but it's a bit too cryptic for me. What's

EDIT:

The code used for my classes is as follows:

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'
    #...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不疑不惑不回忆 2024-09-23 20:37:56

编辑:现在查看了 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_)

Then Meta.__init__DeclarativeMeta.__init__ 都会运行。

Edit: Now having looked at IterRegistry and DeclarativeMeta, I think you're code is okay.

IterRegistry defines __new__ and __iter__, while DeclarativeMeta defines __init__ and __setattr__. Since there is no overlap, there's no direct need to call super. Nevertheless, it would good to do so, to future-proof your code.


Do you have control over the definition of Meta? Can you show us its definition? I don't think we can say it works or does not work unless we see the definition of Meta.

For example, there is a potential problem if your Meta does not call
super(Meta,cls).__init__(classname, bases, dict_)

If you run this code

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

Then only the string 'Meta' gets printed.
In other words, only Meta.__init__ gets run. DeclarativeMeta.__init__ gets skipped.

On the other hand, if you define

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

Then both Meta.__init__ and DeclarativeMeta.__init__ gets run.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文