So testen Sie, ob PyObject einen Iterator hat

8

Ich implementiere eine C-Funktion als Erweiterung für Python. Im Inneren abstract.hfand ich Folgendes:

/* ==== 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 *);

Wenn ich versuche, Iteratoren PyObject_GetIterfür offensichtlich nicht iterierbare Objekte wie eine Zahl zu verwenden, wird der Fehler angezeigt 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);
}

Ich möchte Fehler selbst behandeln. Also habe ich versucht, mit dem PyIter_Checkzu testen, ob das Objekt einen Iterator hat. Diese Funktion gab jedoch 0 für alle von mir bereitgestellten Objekte zurück, einschließlich der iterierbaren.

Ich dachte, dass es durch das PyAPI_FUNC()Makro verursacht werden könnte, aber ich fand es in pyport.hund es scheint nur hinzuzufügen __declspec.

  • Warum gibt die Funktion PyIter_Checkfür alle Objekte Null zurück?
Das Pferd ist braun
quelle

Antworten:

2

PyIter_Checkist zu prüfen , ob ein Objekt ist ein Iterator, nicht , ob es kann bietet ein. Es scheint keine zu geben PyIterable_Check.

Darüber hinaus erzwingt Python EAFP so ziemlich: Da alles __iter__eine Ausnahme auslösen kann , müssen Sie PyObject_GetIterohnehin nach einem Fehler suchen. Der einzige Punkt der *_CheckFunktionen besteht darin, frühzeitige Überprüfungen der Integrität durchzuführen (manchmal mit besseren Fehlermeldungen).

Davis Herring
quelle
Vielen Dank! Super hilfreich. Ich werde die Ausnahmebehandlung studieren :)
thehorseisbrown
@thehorseisbrown: Abgesehen von geeigneten Py_DECREFs für vorhandene Referenzen kann man normalerweise nur sagen PyObject *const x=Py_Foo(…); if(!x) return 0;.
Davis Herring