如何在python

时间:2018-12-22 07:37:00

标签: python c cpython python-c-api

我正在为python编写一个系统调用包装器(就像一个使我习惯API的有趣项目一样),
,当我实现read()时,我困惑于如何修改a发送到我的函数的python缓冲区。

该函数是围绕read()系统调用的简单cpython包装器。
它需要一个整数(文件描述符),一个缓冲区和要读取的最大值,然后返回读取的数量。

除了修改缓冲区外,我一切正常:

py_obj py_read(py_obj self, py_obj args){
    char* buff;
    int fd;
    int len;

    if(!PyArg_ParseTuple(args, "isi", &fd, &buff, &len)){
        return NULL;
    }

    return Py_BuildValue("i", read(fd, buff, len));
}

加载模块后,然后调用read:

>> from syscalls import read
>> STDIN = 1
>> s = ""
>> read(STDIN,s, 256)
napkin
7
>> s
""

尽管这是我的期望(并且应该发生,因为我没有对参数的实际引用),但我想知道如何获得对参数的引用。

编辑: 使用@ user2357112后,它仍然不会修改该值

>>> b = memoryview(b"")
>>> from syscalls import *
>>> read(1, b, 10)
test
5
>>> b
<memory at 0x7fa060628408>
>>> b.tolist()
[]
>>>

编辑2 : 但是如果我正确调整大小,它确实可以与字节数组一起使用 谢谢@ user2357112

1 个答案:

答案 0 :(得分:3)

拥有对该参数的引用。实际上,您可能刚刚破坏了参数对象或参数对象周围的内存。您没有对调用方的s变量的引用,但是无论如何变量和引用在Python中都无法正常工作。引用始终引用对象。

Python字符串对象不适合用作可变缓冲区。毕竟它们应该是一成不变的。另外,它们是Unicode,read读取字节。相反,请使用大小适当的bytearray,并使用y*格式代码通过Py_buffer结构查看其内容。

此外,由于read返回ssize_t而不是int,因此您应该使用n格式代码而不是in对应于Py_ssize_t,当存在ssize_t时,它旨在与ssize_t匹配。

PyObject *my_read(PyObject *self, PyObject *args){
    Py_buffer buff;
    int fd;
    int len;

    if(!PyArg_ParseTuple(args, "iy*i", &fd, &buff, &len)){
        return NULL;
    }

    ssize_t read_count = read(fd, buff.buf, len);
    PyBuffer_Release(&buff);

    return Py_BuildValue("n", read_count);
}