Python: 元类的深入探讨

9 投票
2 回答
760 浏览
提问于 2025-04-16 01:54

我有一个比较冷门的问题,涉及到Python的元类。我正在创建一个Python包,用于服务器端代码,这样可以方便地通过客户端代理访问任意的Python类。为了生成代理代码,我需要一个包含所有我想放入API中的Python类的目录。为此,我使用了一个特殊的属性__metaclass__,来在类创建的过程中插入一个钩子。具体来说,所有在“发布”的API中的类都会继承一个特定的基类PythonDirectPublic,而这个基类本身也有一个__metaclass__,用来记录类创建的信息。

到目前为止,一切都还顺利。但问题变得复杂的是,我希望我的PythonDirectPublic也能继承一个第三方的类(enthought.traits.api.HasTraits)。这个第三方类使用了__metaclass__

那么,管理两个元类的正确方法是什么呢?我的元类应该是Enthought元类的子类吗?还是说我应该在我的元类的__new__方法中调用Enthought的元类,以获取我将要返回的类型对象?或者在这种情况下,还有其他什么神秘的做法吗?

2 个回答

1

具体来说,"published" API中的所有类都会继承一个特定的基类,叫做PythonDirectPublic。

与其再添加一个新的元类,不如递归地使用PythonDirectPublic.subclasses()的结果。

5

我的元类应该是Enthought的元类的子类吗?

我觉得这其实是你唯一的选择。如果你派生类的元类不是它所有基类的元类的子类,那么当你尝试创建这个派生类时,Python会报错,提示类型错误(TypeError)。所以你为 PythonDirectPublic 定义的元类应该像下面这样:

class DerivedMetaClass(BaseMetaClass):
    def __new__(cls, name, bases, dct):
        # Do your custom memory allocation here, if any

        # Now let base metaclass do its memory allocation stuff
        return BaseMetaClass.__new__(cls, name, bases, dct)

    def __init__(cls, name, bases, dct):
        # Do your custom initialization here, if any
        # This, I assume, is where your catalog creation stuff takes place

        # Now let base metaclass do its initialization stuff
        super(DerivedMetaClass, cls).__init__(name, bases, dct)

如果你无法访问第三方基类的元类定义,你可以把 BaseMetaClass 替换成 enthought.traits.api.HasTraits.__metaclass__。虽然这个名字比较长,但这样做是可以的。

撰写回答