Hallo,
mal in der Annahme, das es besser ist, einen neuen Thread auch bei kleinen Fragen zu erstellen, poste ich mal etwas mehr in dieser Sektion
Muss man den RefCount von Objekten, die man an ``PyObject_CallFunctionObjArgs`` und Konsorten übergibt, vorher erhöhen?
Ich _vermute_ nicht, da dazu nichts passendes in der Doku steht, aber bei so etwas wichtigem Frage ich lieber noch einmal nach.
Das mit den Refcounts in der C-API ist ein ziemliches Gewurschtel, aber man bekommt ein Gefühl dafür :-)
Mal angenommen, dass die augerufene Funktion keinen Müll baut mit den Refcounts der übergebenen Objekte, musst du den Refcount nicht erhöhen.
Bekommt eine Routine ein Objekt per Argument übergeben, hat diese ja eigentlich gar nicht die "Berechtigung", den Refcount zu vermindern, weil sie ja quasi nicht der Eigentümer (im Sinne von Ersteller) des Objektes ist. Das meinte ich mit "baut keinen Mist".
Ausnahmen sind natürlich Routinen die explizit Dinge löschen, wie z.B. 'PyDict_DelItem' (hieß doch so?). Und dann gibt es noch ein paar Routinen, die quasi Referenzen "stehlen", hab aber grad keine im Kopf.
Mit dieser kleinen Regel, also eine Routine vermindert den Refcount niemals implizit, wenn sie nicht "Eigentümer" des Objektes ist, schreibt man eigentlich ganz unwurschteligen Code. :-)
@Dauerbaustelle: Zeitersparnis weil man dann der Empfänger den Zähler nicht erhöht und der Aufrufer ihn nicht herunter zählen muss. Und semantisch gesehen überträgt man damit die Verantwortung für das Objekt dem Aufgerufenen.
Keine Ahnung. Vielleicht historisch bedingt. Vielleicht hat auch irgendwer mal geschaut wo es am günstigsten ist. Denn das "stehlen" darf ja nur einmal pro Funktion passieren, wenn man nicht doch wieder den Referenzzähler anpassen will.
Die korrekte Antwort auf diese Frage ist: Nein, wenn die Referenz dir gehört. Ja, wenn sie dir nicht gehört.
Zum Beispiel in dem Fall, dass du einen Aufrufparameter selbst auch nur aus einem dict oder einem Objektattribut genommen hast, gehört dir seine Referenz nicht automatisch. Wenn nun der Funktionsaufruf das Objekt verändert und die Referenz dabei herauslöscht, kann es plötzlich sein, dass sie ganz verschwindet und das Objekt gelöscht wird. -> Crash.
Also, einfache Regel: Immer sicherstellen, dass du eine Referenz hast, die dir auch wirklich gehört (oder sicherstellen, dass der Funktionsaufruf diesbezüglich sicher seiteneffektfrei ist *und* es auch in Zukunft bleibt!)
Ganz wichtig ist das beim Aufruf von C-Funktionen, aber bei Python-Funktionen kann das Problem auch entstehen, wenn der Funktionsaufruf kein Tupel/Dict für die Parameter erzeugt, in dem die Parameter gespeichert sind. Da du darauf meistens keinen Einfluss hast - lieber auf Nummer Sicher gehen.
Cython hatte übrigens auch schon mehr als einmal einen Bug in diesem Bereich, daher ist der generierte Code diesbezüglich inzwischen sehr gut getestet. Deshalb kann ich auch keinem empfehlen, solche Fehler in den eigenen C-Code einzubauen. Besser gleich Cython nehmen.