亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

從 Python C 擴展函數返回參數時需要 INCREF?

從 Python C 擴展函數返回參數時需要 INCREF?

倚天杖 2022-05-11 14:41:44
這個問題很簡單,但有助于鞏固我的理解。我知道 C 擴展函數的參數保證在 C 代碼期間是實時引用(除非手動 DECREFed)。但是,如果我有一個 C 擴展代碼返回其參數列表中存在的 PyObject*,我是否需要在返回它之前 INCREF 參數?即,以下兩項哪一項是正確的:static PyObject return_item(PyObject *self, PyObject *item){    // manipulate item    return item;}或者static PyObject return_item(PyObject *self, PyObject *item){    // manipulate item    Py_INCREF(item);    return item;}基于https://docs.python.org/3/extending/extending.html#ownership-rules,其中說從 Python 調用的 C 函數返回的對象引用必須是擁有的引用——所有權從函數轉移到其調用者。并將對象從 C 返回到 Python我認為是后者(INCREFing 是要走的路),但我想確定。
查看完整描述

2 回答

?
子衿沉夜

TA貢獻1828條經驗 獲得超3個贊

如果有人return_item從 Python 調用函數,他們可能會這樣做:


something = Something()

something_else = return_item(something)

del something

如果return_item沒有返回傳入的參數,而是返回其他內容,您會期望此時something傳入的參數應該從內存中釋放,因為它的引用計數下降到零。


如果你不Py_INCREF返回相同的對象,那仍然會發生 - 對象的引用計數將下降到 0,并且你將在something_else.


TL;DR:是的,你應該這樣做Py_INCREF,因為你通過從函數返回該對象創建了另一個引用。


查看完整回答
反對 回復 2022-05-11
?
米琪卡哇伊

TA貢獻1998條經驗 獲得超6個贊

您不想在返回之前增加對象的引用計數。這樣做會造成內存泄漏,從而阻止對象被垃圾回收。


將引用計數增加為“我正在使用此內存。請不要釋放它”。當你輸入 C 代碼時,你從 Python 中“借用”了引用,但是當你退出 C 代碼時,你已經完成了對象并且不再需要引用了。


Python 中的變量和底層內存是分開的,這使得它在內存方面有些效率(閱讀更多)。另一個答案忽略了分配給something_else增加底層內存的引用計數的事實。您可以使用 自己驗證這一點sys.getrefcount。


import sys

something = "hello"

print(sys.getrefcount(something))       # 2 (getrefcount uses a reference)


something_else = something

print(sys.getrefcount(something_else))  # 3 (same memory as something)


del something

print(sys.getrefcount(something_else))  # 2

print(something_else)                   # "hello"

兩者都something引用something_else了相同的內存(包含文本“hello”的字符串)。刪除一個不會影響另一個。盡管您的代碼使用了 C 函數,但基本原理是相同的。嘗試用你的 C 函數的兩個版本打印出引用計數,它會更清楚。


您不想做的是Py_DECREF在返回對象之前調用。在這種情況下,引用計數可能會降至零,并且返回的東西完全無效。


查看完整回答
反對 回復 2022-05-11
  • 2 回答
  • 0 關注
  • 143 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號