2011-12-16 13 views
11

Piszę moje pierwsze rozszerzenie C do Pythona i jestem zdezorientowany co do moich referencji. Oto, co próbuję zrobić.Liczniki odwołań w rozszerzeniu Python C

I wypełnić dict w pętli for:

mydict = PyDict_New(); 

for (...) 
{ 
    pair = PyTuple_Pack(2, PyString_FromString("some string"), 
      PyString_FromString("some other string")); 

    /* at this point, the refcnt for the tuple is 1, the refcnts for the 
     2 string items are 2. Because according to the source, PyString_FromString 
     does an INCREF, and PyTuple_Pack() does an INCREF on its items 
    */ 

    PyDict_SetItem(mydict, PyString_FromString("some key"), pair); 

    /* At this point, the key's refcnt is 2. PyString_FromString sets it to 1 and 
     PyDict_SetItem INCREF's it. Ditto for pair since PyDict_SetItem also INCREF's 
     the value. 
    */ 

    Py_DECREF(pair); 

    /* pair's refcnt is 1 which makes sense to me since mydict now owns the tuple, 
     but the refcnt for its items are still at 2. I don't understand this part. 
    */ 
} 

return mydict; 

Czy moje liczy ref prawidłowe? W dokumentach interfejsu API C szczególnie zaleca użycie funkcji PyObject_FromXXX jako argumentów dla PyTuple_SetItem lub PyList_SetItem, ponieważ "kradną" odniesienia.

Nie jest udokumentowane, czy PyDict_SetItem przechwytuje odniesienia. Zgaduję, że nie ma w tym przypadku, zrobić

first = PyString_FromString("some string"); 
second = PyString_FromString("some other string"); 
pair = PyTuple_Pack(2, first, second); 
Py_DECREF(second); 
Py_DECREF(first); 

mam rację?

+0

To pytanie wydaje się powiązane: http://stackoverflow.com/questions/6977161/where-should-i-put-py-incref- i-py-decref-na-tym-bloku-w-python-c-rozszerzeniu – Daenyth

+0

Powiązany tak, ale nie duplikat: PyTuple vs PyDict – gecco

Odpowiedz

3

Jeśli spojrzysz na kod źródłowy CPython (Objects/tupleobject.c) dla PyTuple_Pack, zobaczysz, że rzeczywiście zwiększa on liczbę referencyjną dla każdego spakowanego obiektu. Jeśli zamiast tego wykonasz PyTuple_New, a następnie wywołają PyTuple_SetItem, nie będziesz musiał zmniejszać liczby odwołań, ponieważ SetItem wykrada odwołania.

Na koniec możesz po prostu użyć Py_BuildValue ("(ss)", "jakiś ciąg", "jakiś inny ciąg"); będzie budować swój krotki dla Ciebie i stworzy PyStrings dla Ciebie: http://docs.python.org/c-api/arg.html#Py_BuildValue