从同一个C扩展模块中调用不同方法的正确方法?

问题描述 投票:0回答:1

我正在将纯Python模块转换为C扩展,以熟悉C API。

Python实现如下:

_CRC_TABLE_ = [0] * 256

def initialize_crc_table():
    if _CRC_TABLE_[1] != 0:  # Safeguard against re-initialization
        return
    # snip

def calculate_crc(data: bytes, initial: int = 0) -> int:
    if _CRC_TABLE_[1] == 0:  # In case user forgets to initialize first
        initialize_crc_table()
    # snip

# additional non-CRC methods trimmed

到目前为止,我的C扩展名有效:

#include <Python.h>

static Py_ssize_t CRC_TABLE_LEN = 256;
PyObject *_CRC_TABLE_;

static PyObject *method_initialize_crc_table(PyObject *self, PyObject *args) {
   // snip
}

static PyMethodDef module_methods[] = {
  {"initialize_crc_table", method_initialize_crc_table, METH_VARARGS, NULL},
  {NULL, NULL, 0, NULL}
};

void _allocate_table_() {
  _CRC_TABLE = PyList_New(CRC_TABLE_LEN);
  PyObject *zero = Py_BuildValue("i", 0);
  for (int i = 0; i < CRC_TABLE_LEN; i++) {
    PyList_SetItem(_CRC_TABLE_, i, zero);
  }
}

#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef module_utilities = {
  PyModuleDef_HEAD_INIT,
  "utilities",
  NULL,
  -1,
  module_methods,
};

PyMODINIT_FUNC PyInit_utilities() {
  PyObject *module = PyModule_Create(&module_utilities);
  _allocate_table_();
  PyModule_AddObject(module, "_CRC_TABLE", _CRC_TABLE_);
  return module;
}
#else
PyMODINIT_FUNC initutilities() {
  PyObject *module = Py_InitModule3("utilities", module_methods, NULL);
  _allocate_table_();
  PyModule_AddObject(module, "_CRC_TABLE", _CRC_TABLE_);
}

我能够从解释器的C扩展名访问utilities._CRC_TABLE_,并且在调用utilities.intialize_crc_table时值与Python等效。

现在,我尝试在initialize_crc_table的开头调用calculate_crc,执行与Python实现中相同的检查。我现在返回None

static PyObject *method_calculate_crc(PyObject *self, PyObject *args) {
  if (!(uint)PyLong_AsUnsignedLong(PyList_GetItem(_CRC_TABLE_, (Py_ssize_t) 1))) {
    PyObject *call_initialize_crc_table = PyObject_GetAttrString(self, "initialize_crc_table");
    PyObject_CallObject(call_initialize_crc_table, NULL);
    Py_DECREF(call_initialize_crc_table);
  }
  Py_RETURN_NONE;
}

我已将此添加到module_methods[],并且它编译时没有警告或错误。当我在解释器中运行此方法时,我遇到了段错误。我认为这是因为self不是作为对象的模块。

我可以这样做,这似乎没有问题:

static PyObject *method_calculate_crc(PyObject *self, PyObject *args) {
  if (!(uint)PyLong_AsUnsignedLong(PyList_GetItem(_CRC_TABLE_, (Py_ssize_t) 1))) {
    method_initialize_crc_table(self, NULL);
  }
  Py_RETURN_NONE;
}

但是,我不确定是否应该将selfNULL或其他内容传递给该方法。

method_initialize_crc_table调用method_calculate_crc的正确方法是什么?

我正在将纯Python模块转换为C扩展名,以熟悉C API。 Python实现如下:_CRC_TABLE_ = [0] * 256 def initialize_crc_table():if ...

python-c-api python-extensions
1个回答
0
投票

这里有一个“陷阱”,我必须澄清。虽然代码是为Python 3设计的,但是开发最初是在Python 2中完成的,因为开发文件在我使用的机器上尚不可用。这揭示了每个版本在处理方式上的一些差异。大卫的评论有助于澄清。

© www.soinside.com 2019 - 2024. All rights reserved.