Title: Add Py_HOLD_REF() macro to hold a strong reference to a Python object while executing code · Issue #99481 · python/cpython · GitHub
Open Graph Title: Add Py_HOLD_REF() macro to hold a strong reference to a Python object while executing code · Issue #99481 · python/cpython
X Title: Add Py_HOLD_REF() macro to hold a strong reference to a Python object while executing code · Issue #99481 · python/cpython
Description: Reference counting in Python is complicated. It's never obvious if we are holding a strong reference or a borrowed reference to a Python object. If we have a borrowed reference to a Python object, to make sure that it cannot be deleted w...
Open Graph Description: Reference counting in Python is complicated. It's never obvious if we are holding a strong reference or a borrowed reference to a Python object. If we have a borrowed reference to a Python object, ...
X Description: Reference counting in Python is complicated. It's never obvious if we are holding a strong reference or a borrowed reference to a Python object. If we have a borrowed reference to a Python obje...
Opengraph URL: https://github.com/python/cpython/issues/99481
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Add Py_HOLD_REF() macro to hold a strong reference to a Python object while executing code","articleBody":"Reference counting in Python is complicated. It's never obvious if we are holding a strong reference or a borrowed reference to a Python object.\r\n\r\nIf we have a **borrowed reference** to a Python object, to make sure that it cannot be deleted while we execute **arbitrary Python code**, it's needed to creating a temporary **strong reference** by increasing temporarily its reference counter. Example from ``Modules/_abc.c``:\r\n\r\n~~~\r\n subclasses = PyObject_CallMethod(self, \"__subclasses__\", NULL);\r\n (...)\r\n PyObject *scls = PyList_GET_ITEM(subclasses, pos);\r\n\r\n Py_INCREF(scls); // create a temporary strong reference\r\n int r = PyObject_IsSubclass(subclass, scls);\r\n Py_DECREF(scls); // delete the temporary strong reference\r\n~~~\r\n\r\nThe **scls** variable is assigned to a **borrowed reference** to a list item. The list is the result of the ``__subclasses__()`` method. The code creates a temporarily **strong reference** to call ``PyObject_IsSubclass()``.\r\n\r\nIMO in terms of semantics, such code is hard to understand if read aloud in English, since INCREF and DECREF modify the object **in-place**. Py_INCREF() and Py_DECREF() are like the low-level implementation, I would prefer to have an abstraction on top of it.\r\n\r\nThat's also why I added ``Py_NewRef()`` in Python 3.10: Py_NewRef() semantics is simpler: it **creates a new strong reference**. In terms of semantics, it doesn't modify the object in-place, even if it's possible to write something like ``var = Py_NewRef(var)`` (I discourage to write such code). See issue #99300 for the usage of the Py_NewRef() function.\r\n\r\nIt would be nice to have a macro to clarify the scope of the temporary strong reference rather than having to INCREF/DECREF temporarily. Something like:\r\n\r\n```c\r\n#define Py_HOLD_REF(var, code) \\\r\n Py_INCREF(var); \\\r\n code; \\\r\n Py_DECREF(var)\r\n```\r\n\r\nExample of usage:\r\n\r\n```c\r\nPy_HOLD_REF(scls,\r\n int r = PyObject_IsSubclass(subclass, scls);\r\n);\r\n```\r\n\r\nExample holding two (different) strong references:\r\n\r\n```c\r\nPy_HOLD_REF(keys,\r\n Py_HOLD_REF(values,\r\n PyObject *res = PyTuple_Pack(2, keys, values);\r\n ) // note: there is no \";\" here\r\n);\r\n```\r\n\r\nAlternative compact syntax:\r\n\r\n```c\r\nPy_HOLD_REF(keys, Py_HOLD_REF(values,\r\n PyObject *res = PyTuple_Pack(2, keys, values);\r\n));\r\n```\r\n\r\nObviously, the macro name is open for bikeshedding :-)","author":{"url":"https://github.com/vstinner","@type":"Person","name":"vstinner"},"datePublished":"2022-11-14T16:24:57.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/99481/cpython/issues/99481"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:e26bd55f-83c5-527f-d7e4-b4069702afd2 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 9EB4:134C26:2088C45:2B1225B:696B0878 |
| html-safe-nonce | 55d7c1430e531a999771d993d6d42435412fb93c0853105a37295382e069ac1c |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5RUI0OjEzNEMyNjoyMDg4QzQ1OjJCMTIyNUI6Njk2QjA4NzgiLCJ2aXNpdG9yX2lkIjoiMzc3Mjc4OTY5NjUyMTUwNDg4OCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 770f06cbb6273097361b6ab01dd4a4977dd7bb0d30c99d4ff7c2f3e73c0ea655 |
| hovercard-subject-tag | issue:1448369558 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/99481/issue_layout |
| twitter:image | https://opengraph.githubassets.com/2ee225497b1b9117626c0b0556f4fa8ab2733fc2ea8b5960edd6a216fec136d5/python/cpython/issues/99481 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/2ee225497b1b9117626c0b0556f4fa8ab2733fc2ea8b5960edd6a216fec136d5/python/cpython/issues/99481 |
| og:image:alt | Reference counting in Python is complicated. It's never obvious if we are holding a strong reference or a borrowed reference to a Python object. If we have a borrowed reference to a Python object, ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | vstinner |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5f99f7c1d70f01da5b93e5ca90303359738944d8ab470e396496262c66e60b8d |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 82560a55c6b2054555076f46e683151ee28a19bc |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width