-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update documentation refcounting example (#6180)
I think this makes some of the different behaviour clearer. The initial example was somewhat complicated by things like "is sys.getrefcount creating an extra reference?", and reading global variables inside the functions which isn't hugely relevant to much. This tries to show the effect of creating new references inside a function, which is more direct and probably shows what we actually want.
- Loading branch information
Showing
3 changed files
with
50 additions
and
25 deletions.
There are no files selected for viewing
35 changes: 23 additions & 12 deletions
35
docs/examples/userguide/language_basics/parameter_refcount.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,34 @@ | ||
from cython.cimports.cpython.ref import PyObject, _Py_REFCNT | ||
# Py_REFCNT and _Py_REFCNT are the same, except _Py_REFCNT takes | ||
# a raw pointer and Py_REFCNT takes a normal Python object | ||
from cython.cimports.cpython.ref import PyObject, _Py_REFCNT, Py_REFCNT | ||
|
||
import sys | ||
|
||
python_dict = {"abc": 123} | ||
python_dict_refcount = sys.getrefcount(python_dict) | ||
python_dict_refcount = Py_REFCNT(python_dict) | ||
|
||
@cython.cfunc | ||
def owned_reference(obj: object): | ||
refcount = sys.getrefcount(python_dict) | ||
print('Inside owned_reference: {refcount}'.format(refcount=refcount)) | ||
refcount1 = Py_REFCNT(obj) | ||
print(f'Inside owned_reference initially: {refcount1}') | ||
another_ref_to_object = obj | ||
refcount2 = Py_REFCNT(obj) | ||
print(f'Inside owned_reference after new ref: {refcount2}') | ||
|
||
@cython.cfunc | ||
def borrowed_reference(obj: cython.pointer(PyObject)): | ||
# use _Py_REFCNT instead of Py_REFCNT to avoid creating a new owned | ||
# reference just to get the reference count | ||
refcount = _Py_REFCNT(obj) | ||
print('Inside borrowed_reference: {refcount}'.format(refcount=refcount)) | ||
refcount1 = _Py_REFCNT(obj) | ||
print(f'Inside borrowed_reference initially: {refcount1}') | ||
another_ptr_to_object = obj | ||
refcount2 = _Py_REFCNT(obj) | ||
print(f'Inside borrowed_reference after new pointer: {refcount2}') | ||
# Casting to a managed reference to call a cdef function doesn't increase the count | ||
refcount3 = Py_REFCNT(cython.cast(object, obj)) | ||
print(f'Inside borrowed_reference with temporary managed reference: {refcount3}') | ||
# However calling a Python function may depending on the Python version and the number | ||
# of arguments. | ||
|
||
def main(): | ||
print('Initial refcount: {refcount}'.format(refcount=python_dict_refcount)) | ||
owned_reference(python_dict) | ||
borrowed_reference(cython.cast(cython.pointer(PyObject), python_dict)) | ||
|
||
print(f'Initial refcount: {python_dict_refcount}') | ||
owned_reference(python_dict) | ||
borrowed_reference(cython.cast(cython.pointer(PyObject), python_dict)) |
33 changes: 22 additions & 11 deletions
33
docs/examples/userguide/language_basics/parameter_refcount.pyx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,34 @@ | ||
from cpython.ref cimport PyObject, _Py_REFCNT | ||
# Py_REFCNT and _Py_REFCNT are the same, except _Py_REFCNT takes | ||
# a raw pointer and Py_REFCNT takes a normal Python object | ||
from cpython.ref cimport PyObject, _Py_REFCNT, Py_REFCNT | ||
|
||
import sys | ||
|
||
python_dict = {"abc": 123} | ||
python_dict_refcount = sys.getrefcount(python_dict) | ||
python_dict_refcount = Py_REFCNT(python_dict) | ||
|
||
|
||
cdef owned_reference(object obj): | ||
refcount = sys.getrefcount(python_dict) | ||
print('Inside owned_reference: {refcount}'.format(refcount=refcount)) | ||
refcount1 = Py_REFCNT(obj) | ||
print(f'Inside owned_reference initially: {refcount1}') | ||
another_ref_to_object = obj | ||
refcount2 = Py_REFCNT(obj) | ||
print(f'Inside owned_reference after new ref: {refcount2}') | ||
|
||
|
||
cdef borrowed_reference(PyObject * obj): | ||
# use _Py_REFCNT instead of Py_REFCNT to avoid creating a new owned | ||
# reference just to get the reference count | ||
refcount = _Py_REFCNT(obj) | ||
print('Inside borrowed_reference: {refcount}'.format(refcount=refcount)) | ||
|
||
|
||
print('Initial refcount: {refcount}'.format(refcount=python_dict_refcount)) | ||
refcount1 = _Py_REFCNT(obj) | ||
print(f'Inside borrowed_reference initially: {refcount1}') | ||
another_ptr_to_object = obj | ||
refcount2 = _Py_REFCNT(obj) | ||
print(f'Inside borrowed_reference after new pointer: {refcount2}') | ||
# Casting to a managed reference to call a cdef function doesn't increase the count | ||
refcount3 = Py_REFCNT(<object>obj) | ||
print(f'Inside borrowed_reference with temporary managed reference: {refcount3}') | ||
# However calling a Python function may depending on the Python version and the number | ||
# of arguments. | ||
|
||
|
||
print(f'Initial refcount: {python_dict_refcount}') | ||
owned_reference(python_dict) | ||
borrowed_reference(<PyObject *>python_dict) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters