Cách kiểm tra nếu PyObject có iterator


8

Tôi đang thực hiện một hàm C như một phần mở rộng cho Python. Bên trong abstract.h, tôi tìm thấy như sau:

/* ==== Iterators ================================================ */

/* Takes an object and returns an iterator for it.
   This is typically a new iterator but if the argument is an iterator, this
   returns itself. */
PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *);

/* Returns 1 if the object 'obj' provides iterator protocols, and 0 otherwise.

   This function always succeeds. */
PyAPI_FUNC(int) PyIter_Check(PyObject *);

Khi tôi cố gắng để các trình vòng lặp sử dụng PyObject_GetItertrên các đối tượng rõ ràng không thể lặp như số, tôi gặp lỗi SystemError: <built-in function xxx> returned a result with an error set.

static PyObject *my_method(PyObject *self, PyObject *args) 
{
    PyObject *obj;
    PyArg_ParseTuple(args, "O", &obj)
    //  printf("\ncheck %d",PyIter_Check(obj)); // always 0
    PyObject *iter = PyObject_GetIter(obj); // throws error
    return PyLong_FromLong(0);
}

Tôi muốn tự xử lý lỗi. Vì vậy, tôi đã cố gắng sử dụng PyIter_Checkđể kiểm tra nếu đối tượng có một trình vòng lặp. Tuy nhiên, hàm này trả về 0 cho tất cả các đối tượng tôi cung cấp, bao gồm cả các đối tượng lặp.

Tôi nghĩ rằng nó có thể được gây ra bởi PyAPI_FUNC()macro nhưng tôi đã tìm thấy nó pyport.hvà dường như nó chỉ được thêm vào __declspec.

  • Tại sao hàm PyIter_Checktrả về 0 cho tất cả các đối tượng?

Câu trả lời:


2

PyIter_Checklà để kiểm tra xem một đối tượng có phải là một trình vòng lặp không, liệu nó có thể cung cấp một đối tượng hay không . Dường như không cóPyIterable_Check .

Hơn nữa, Python thực thi khá nhiều EAFP: vì bất cứ điều gì có thể cung cấp __iter__ngoại lệ, bạn phải kiểm tra lỗi từ PyObject_GetItermọi cách, vì vậy điểm duy nhất của các *_Checkchức năng là cung cấp kiểm tra độ tỉnh táo sớm (đôi khi có thông báo lỗi tốt hơn).


Cảm ơn bạn! Siêu hữu ích. Tôi sẽ nghiên cứu xử lý ngoại lệ :)
thehorseisbrown 2/12/19

@thehorseisbrown: Ngoài Py_DECREFcác tài liệu tham khảo thuộc sở hữu còn tồn tại, bạn thường chỉ có thể nói PyObject *const x=Py_Foo(…); if(!x) return 0;.
Davis Herring
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.