You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cython中实现SlotsMeta元类遇问题,求解决方案

Cython元类SlotsMeta实现问题

我想在Cython里实现一个名为SlotsMeta的元类,目标是让使用这个元类的类,其所有类变量都变成Cython中的readonly属性。我的思路是把元类__cinit__方法传入的**kwargs里的类变量(作为键)转成Tuple[str],再赋值给SlotsMeta.__slots__。

参考了以下资料:

  • Python Metaclass defining slots makes slots readonly
  • sagelib的classcall_metaclass.pxd实现
  • sagelib的classcall_metaclass.pyx实现

我的Cython实现代码如下:

#cython: language_level=3
# copied from sagelib的classcall_metaclass.pyx
from cpython cimport PyObject, Py_XDECREF

cdef extern from "Python.h":
    ctypedef PyObject *(*callfunc)(type, object, object) except NULL
    ctypedef struct PyTypeObject_call "PyTypeObject":
        callfunc tp_call # needed to call type.__call__ at very high speed.
    cdef PyTypeObject_call PyType_Type # Python's type

cdef class SlotsMeta(type):
    cdef readonly tuple __slots__

    def __init__(mcls, str name, tuple bases, dict attrs):
        attrs_keys = tuple(str(k) for k in attrs.keys())
        mcls.__slots__ = attrs_keys

    def __call__(cls, *args, **kwargs):
        ptr = PyType_Type.tp_call(cls, args, kwargs)
        inst = <object>ptr
        inst.__init__(*args, **kwargs)
        Py_XDECREF(ptr) # During the cast to <object> Cython did INCREF(res)
        return inst

测试代码执行失败:

class A(metaclass=SlotsMeta):
    B: str = "H"
 
    
def test_slotsmeta():
    a = A() # passes
    assert a.B == "H" # passes
    with pytest.raises(AttributeError): # passes
        a.C # passes
    with pytest.raises(AttributeError):
        a.C = 500 # failed
        
    assert a.__slots__ == ("B", ) # failed

目前遇到的问题:

  • 本应无法给实例a添加属性C(a.C = 500),但实际可以执行成功
  • a.__slots__应该返回("B",),但实际没有返回预期值
  • 实例a的__dict__本不应存在,但实际存在

内容的提问来源于stack exchange,提问作者Jim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:13:15