Cython无法使用setattr

4 投票
1 回答
776 浏览
提问于 2025-04-18 08:14

我在Cython中有一个cdef类,我想用setattr这个内置函数来初始化它的字段。不过,当我这么做的时候,出现了执行错误:

/path/.../cimul.cpython-34m.so in cimul.Simulation.__init__ (cimul.c:5100)()
AttributeError: 'Simulation' object has no attribute 'Re'

我的代码如下:

cdef class Simulation:
    cdef double Re, Pr, Ra, a, dt_security
    cdef int Nz, NFourier, freq_output, freq_critical_Ra, maxiter
    cdef bool verbose

    def __init__(self, *args, **kargs):
        param_list = {'Re': 1, 'Pr': 1, 'Ra': 1, 'a' : 1, 'Nz': 100,
                      'NFourier': 50, 'dt_security': 0.9,
                      'maxiter': 100, 'freq_output': 10,
                      'freq_critical_Ra':50, 'verbose': False}
        # save the default parameters
        for param, value in param_list.items():
            setattr(self, param, value)

你有没有什么办法可以解决这个问题?

1 个回答

2
  • 当你在一个类里用cdef定义属性(没有加public)时,其实是在定义一个C语言结构体里的字段。因此,在编译后(Cython和C一起),这些属性的名字就消失了,它们只能通过在C结构体开头的偏移量来识别。所以,这些属性在Python中是无法访问的。

  • 如果你加上cdef public,Cython会自动添加一些property访问函数,这样不仅可以从Python访问这些属性,还能保持属性名和C结构体中的偏移量之间的关联。不过,通过这些属性函数访问会稍微慢一点。此外,这些函数还会进行Python和C之间的数据类型检查和转换。

现在,针对你的问题,你需要某种方式来保持属性名和偏移量之间的关联。如果你想要速度快,唯一的方法就是手动处理:

self.RE = param_list['RE']   # self.RE is a C struct access
self.Pr = param_list['Pr']
...

撰写回答