簡體   English   中英

(Python) Monkeypatch __new__ 用於 python 中的 int、float、str、list、dict、set 和 module 類型的對象

[英](Python) Monkeypatch __new__ for objects of type int, float, str, list, dict, set, and module in python

我想用自定義構建的替換(擴展)隱式擴展 int、float、str、list、dict、set 和 module 類。

當我說“隱式”時,我的意思是當我聲明“a = 1”時,會生成 Custom_Int 類型的 object(例如),而不是正常的 integer ZA8CFDE63311949EB2AC96B8。

現在,我理解並尊重不這樣做的理由。 首先,弄亂內置插件就像弄亂物理定律。 沒有任何好處可以從中得到。 就是說-我確實了解我正在嘗試做的事情的嚴重性,以及如果我做錯了會發生什么。

其次-我知道修改基本案例不僅會影響當前運行時,還會影響所有正在運行的 python 進程。 我覺得通過覆蓋這些基類的 __new__ 方法,當且僅當某些環境因素為真時,它返回 Custom_Object_Whatever,其他運行時間將基本不受影響。

那么,回到手頭的問題——如何覆蓋這些不同類型的 __new__ 方法?

蟒蛇forbiddenfruit package似乎很有希望。 不過,我還沒有機會對其進行仔細調查,如果了解它的人可以總結一下它的作用,那將為我節省很多時間。

除此之外,我觀察到一些奇怪的事情。

對於monkeypatching 的每一個答案最終都不會回到forbiddenfruit 或forbiddenfruit 的工作原理,這與修改我將稱為class 的“absolute_dictionary”的內容有關。 因為 Python 中的所有內容本質上都是函數/值到名稱的映射(或字典),所以如果您在正確的映射中更改名稱 __new__,您將更改 object 的性質。

問題是 - 我所取得的每一個近乎成功的情況是,如果我調用 'str('a').__new__(*args)' 它可以正常工作{在某些情況下} ,但調用 varOne = 'a' 確實似乎並沒有真正調用 str.__new__()。

我的猜測-這與 python 在啟動之前解析程序有關,或者與啟動期間/發布后的各種類的緩存有關。 或者,也許我完全不合時宜。 python 在啟動之前預讀取並將一些正則表達式應用到它的模塊,或者機器代碼,當它試圖隱式創建 object 時,它會到達位於 Object.

有任何想法嗎?

如果您想這樣做,您最好的選擇可能是修改 CPython 源代碼並構建您自己的自定義 Python 構建,並將您的擴展烘焙到實際的內置類型中。 結果將與所有你還不了解的低級機制更好地集成,並且你會在這個過程中學到很多東西。


現在,你受到很多因素的阻礙。 以下是我想到的。

首先是大多數創建內置對象的方法根本不是通過__new__方法 go 。 他們 go 通過像PyLong_FromLongPyList_New這樣的 C 級調用。 這些調用硬連線以使用實際的內置類型,分配 memory 大小為真正的內置類型,獲取類型 object 通過其靜態分配的地址 Z0D61F8370CAD1D4D412F80B84D1 之類的東西。 如果不構建自己的自定義 Python,則基本上不可能更改任何內容。

第二個因素是,弄亂__new__甚至不足以正確影響理論上應該 go 到__new__的事情,例如int("5") Python 有理由阻止您在內置類上設置屬性,其中兩個原因是插槽類型屬性緩存

插槽是 C API 的公共部分,如果您嘗試修改 CPython 源代碼,您可能會了解它。 它們是 C 結構中的 function 指針,構成 C 級別的類型對象,其中大多數對應於 Python 級別的魔術方法。 例如, __new__方法有一個對應的tp_new槽。 大多數 C 代碼訪問插槽而不是方法,並且有代碼可以確保插槽和方法同步,但是如果您繞過 Python 的保護,那就會中斷,一切都會搞砸。

即使在 C 級別, 類型屬性緩存也不是任何東西的公共部分。 它是一個緩存,保存類型 object 屬性查找的結果,以使 Python go 更快。 Its memory safety relies on all type object attribute modification going through type.__setattr__ (and all built-in type object attribute modification getting rejected by type.__setattr__ ), but if you bypass the protection, memory safety goes out the window and arbitrarily weird results可以發生。

第三個因素是不可變對象有大量緩存。 小的 int 緩存、interned string dict、保存在字節碼對象中的常量、編譯時常量折疊……還有很多。 不會在您期望的時候創建對象。 (還有諸如zip之類的東西,保存最后一個 output 元組並在它看到您沒有保留參考時重復使用它,以獲取更多 object 創建的方法)。

還有更多。 類似的東西,如果您嘗試使用int.__new__來評估表達式5 ,那么int.__new__甚至會采用什么參數? 就像所有低級代碼一樣,它們確切地知道如何使用它所期望的類型,並且如果它得到一個具有與真實元組完全不同的 memory 布局的MyCustomTuple ,將會變得非常困惑。 用內置插件擰緊有很多問題。

順便說一句,您期望成為問題的一件事大多不是問題。 使用一個 Python 進程的內置程序不會影響其他 Python 進程的內置程序......除非這些其他進程是通過分叉第一個進程創建的,例如在 fork 模式下使用multiprocessing

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM