我想創建一個類,它的行為類似于 numpy 陣列,但擁有額外的方法/屬性,并且一直在閱讀但沒有完全理解 numpy關于 ndarray 子類化的指南。在那個網頁上有一個例子,上面寫著
import numpy as np
class RealisticInfoArray(np.ndarray):
def __new__(cls, input_array, info=None):
# Input array is an already formed ndarray instance
# We first cast to be our class type
obj = np.asarray(input_array).view(cls)
# add the new attribute to the created instance
obj.info = info
# Finally, we must return the newly created object:
return obj
def __array_finalize__(self, obj):
# see InfoArray.__array_finalize__ for comments
if obj is None: return
self.info = getattr(obj, 'info', None)
我很困惑為什么這些線
obj = np.asarray(input_array).view(cls)
# add the new attribute to the created instance
obj.info = info
不提高
AttributeError: 'numpy.ndarray' object has no attribute 'info'
我在運行時將屬性添加到 Numpy 陣列中讀到它與在 C 中實作的 numpy 陣列有關。這是故事的結尾嗎?Python 如何“知道” np.array 是用 C 實作的,而不是可以輕松添加新屬性的 Python 類?
uj5u.com熱心網友回復:
C 實作的類必須竭盡全力擁有一個__dict__(這是存盤動態定義的屬性的地方);他們可以做到,但他們通常不會,除非他們試圖模擬其他允許它的型別(例如,functools.partial允許您分配任意屬性,因為常規函式允許它,并且它試圖保持兼容),因為他們有更多存盤其預定義屬性集的有效方法(通常作為PyObject標頭中的原始值或指標)。
省略__dict__每個實體可以節省一個指標的記憶體開銷(4-8 位元組),加上實際dict本身的成本(即使__dict__在 64 位 CPython 3.9.5 上為空,也需要 104 位元組)。對于您創建許多實體的簡單型別,包括__dict__幾乎從不使用的情況會大量增加開銷。例如,CPython 3.9.5 x64float消耗 24 位元組來存盤 8 位元組的“真實”資料,這意味著 16 位元組是開銷;如果它允許任意屬性分配,即使__dict__是惰性創建的,開銷也會從 16 位元組跳到 24 位元組,如果不是惰性創建的(通過洗掉對“允許”的檢查來加速其他代碼)__dict__但它可能尚未初始化”,必須在每次訪問時執行)開銷將從 24 位元組跳到 128 位元組(加上分配器開銷的兩倍,以浪費未嚴格分配的位元組,但會丟失到舍入-off 和碎片問題),所有這些都只是 8 位元組的“真實”資料。存盤 500 萬個floats 將使 40 MB 的原始 C 成本變為__dict__120 MB的-less CPython 成本(忽略實際保存它們的容器;即將至少增加 40 MB) 到 680 MB,所有這些都是偶然的,您可能希望在其中一個上定義任意屬性。
另一方面,用戶定義的類__dict__默認具有(默認情況下,這是它們存盤屬性的唯一地方,無論__init__是在類中定義還是由類的使用者手動添加),并且僅在類及其所有父類定義時才省略它一個類級別__slots__(并且僅當它們都從它們的 中省略'__dict__'時__slots__)。
要回答您的具體問題“Python 如何“知道”np.array 是用 C 實作的,而不是您可以輕松添加新屬性的 Python 類?” ,至少對于 CPython,它測驗tp_dictoffset實體的類是否為非零;如果它為零,則該類的實體缺少__dict__并且添加任意屬性是不合法的,如果它不為零,則它告訴解釋器PyObject它需要查找的標頭的開頭(或結尾,如果為負)有多少位元組__dict__指標。tp_dictoffset在定義類時初始化,在想要支持任意屬性的 C 實作類的情況下手動初始化,并由用戶定義類的解釋器機器代表您。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/362181.html
上一篇:回傳另一個泛型型別的泛型
