Как изменить значение переменной Python (например, ссылки) в Python - PullRequest
0 голосов
/ 22 декабря 2018

Я пишу оболочку системного вызова для Python (просто как забавный проект, чтобы научить меня использовать API),
и когда я пришел к реализации read (), я озадачен тем, как я могу изменить Pythonбуфер, который отправляется моей функции.

Функция представляет собой простую оболочку cpython для системного вызова read ().
Требуется целое число (дескриптор файла), буфер и максимум, который вы хотите получить.прочитайте, затем верните сумму, прочитанную.

У меня все работает, кроме модификации буфера:

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 : Но он работает с bytearray, если я его правильно измерил Спасибоyou @ user2357112

1 Ответ

0 голосов
/ 22 декабря 2018

У вас есть ссылка на аргумент.Вы, возможно, только что испортили объект аргумента или память, окружающую его.У вас нет ссылки на переменную s вызывающей стороны, но переменные и ссылки так или иначе не работают в Python;ссылки всегда ссылаются на объекты.

Строковые объекты Python не подходят для использования в качестве изменяемых буферов.В конце концов, они должны быть неизменными.Кроме того, они Unicode, и read читает байты.Вместо этого используйте bytearray соответствующего размера и просмотрите его содержимое через структуру Py_buffer с кодом формата y*.

Кроме того, поскольку read возвращает ssize_t вместо int, вы должны использовать код формата n вместо i.n соответствует 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);
}
...