【问题标题】:Avoid garbage collection of C written Python library避免 C 编写的 Python 库的垃圾收集
【发布时间】:2017-01-18 10:59:04
【问题描述】:

我正在为我的 C 编写的 Python 库而苦苦挣扎。该代码旨在在 cp210x 中写入一个寄存器,以控制继电器卡。代码有效,但是 Python 以某种方式清除了该对象。

也就是说,C 变量 ttyPort 在函数结束后被清除。

这是 C 代码:

#include <Python.h>
#include <fcntl.h>
#include <stropts.h>

// C variable that holds the tty address (e.g. /dev/ttyUSB0)
const char* ttyPort;

int setRelay(int action, int relayNumber)
{
    /* more magic over here */
    printf("Port :: %s\n", ttyPort);

}
// All python wrappers below

static PyObject*setPort(PyObject* self, PyObject* args)
{
    Py_INCREF(self)
    // Copy python argument to ttyPort
    if (!PyArg_ParseTuple(args, "s", &ttyPort))
        return NULL;

    printf("RelayModule :: Port set (%s)\n", ttyPort);

    Py_RETURN_NONE;
}

static PyObject*fanOff(PyObject* self, PyObject* args)
{
    //fanMode = 0;
    printf("RelayModule :: Fan off %s\n",ttyPort);
    if (setRelay(RELAY_OFF, 0) == 1){
        // more magic
    }
    Py_RETURN_NONE;
}
/* more functions over here */
static PyMethodDef RelayMethods[] =
{
     {"setPort", setPort, METH_VARARGS, "Set tty port."},
     {"fanOff", fanOff, METH_NOARGS, "Fan off."},
     {"fanHalf", fanHalf, METH_NOARGS, "Fan half speed."},
     {"fanFull", fanFull, METH_NOARGS, "Fan full on."},
     {"pumpOn", pumpOn, METH_NOARGS, "Pump on."},
     {"pumpOff", pumpOff, METH_NOARGS, "Pump off."},
     {"isPumpOn", isPumpOn, METH_NOARGS, "Check if pump is on."},
     {"getFanMode", getFanMode, METH_NOARGS, "Get fan mode."},
     {NULL, NULL, 0, NULL}
};

static struct PyModuleDef RelayDefs = { 
    PyModuleDef_HEAD_INIT,"RelayModule","A Python module that controls the Conrad 4ch relay card.", -1, RelayMethods 
};


PyMODINIT_FUNC PyInit_Relay(void)
{
    Py_Initialize();
    return PyModule_Create(&RelayDefs);
}

以python代码为例:

import Relay

def settty():
    Relay.setPort("/dev/ttyUSB0")

def gettty():
    Relay.fanOff()

def doAll():
    Relay.setPort("/dev/ttyUSB0")
    Relay.fanOff()

settty()
gettty() #Error, prints 'Port :: [garbage]'
doAll() #works!

我怎样才能以某种方式声明一个对象?在其他语言中,我会这样做: RelayObj = new Relay()

或者如何正确存储变量?

【问题讨论】:

  • 将其嵌入到对象中并使函数成为成员函数。
  • 我认为主要问题之一是我将如何做到这一点
  • 使用您当前的实现,尝试将PyModule_Create 的返回值存储在静态变量中。我怀疑立即返回它可能会导致优化器立即将其删除(或禁用编译器优化以查看它是否确实干扰)。
  • 点赞:class myrelay(Relay): ... def __init__(self, name): ...(以及其他功能)。然后您可以使用thisrelay = myrelay( '/dev/ttyS0' ) 进行实例化
  • class myrelay(Relay): def __init__(self, name): self.setPort(name) 不起作用,返回类似module.__init__() takes at most 2 arguments (3 given)的错误

标签: python c python-c-api


【解决方案1】:

一种可能的解决方法是在PyArg_ParseTuple(args, "s", &amp;ttyPort) 中使用“es”格式说明符而不是“s”。来自文档:

一般来说,当一个格式设置一个指向缓冲区的指针时,缓冲区由对应的Python对象管理,缓冲区共享这个对象的生命周期

除非你使用'es'。但是,您必须手动释放内存。

【讨论】:

  • 看起来这解决了我的问题,但是我还需要像这样添加编码:if (!PyArg_ParseTuple(args, "es", "utf-8", &amp;ttyPort))
猜你喜欢
  • 1970-01-01
  • 2018-03-15
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多