我是一個Python輕度使用者+愛好者,這兩天我嘗試用Python替代bash完成一些簡單的工作(最主要的目的其實是學習),有一些困惑。
Python不能很方便的定義常量,這就帶來了一些問題,如果一個程式或引用的第三方庫,不小心修改了某一個模組下的一個全域變數,比如re模組的re.I,re.M等,這樣就會給程式帶來很大的不確定性?
re這個例子只不過是一個曆史遺留問題,是特例,還是類似的例子在Python中是普遍存在的?
回複內容:
“修改某一模組下的全域變數”,這就是打猴子補丁啊(Monkey patch
)。Python的設計思想就是要足夠動態,讓你方便運行時各種魔改,你看他連private關鍵字都沒,還可以運行著運行著把自己底層標準庫給換了(比如gevent裡面的monkey patch),區區常量算個毛。你說的事是普遍存在的。python中任何一個名字都只是個簡單綁定,它的實體是什麼這一點你隨時可以改。像_和__這種用來表示私人的首碼效果也不過是自動改個名而已。這提供了足夠高的自由度,讓程式員在不直接修改模組的前提下可以改動其內的行為,同時要求程式員自己不要無故作死。像re.M這樣的量,關鍵不在於可不可改,而是應不應該去改。
當然這是不安全的。拿JAVA來做對比就會明白Python在安全性上維持的重點在程式員自身。這也是為啥招個『初級』Python程式員會坑死。
當然了,一些特殊的手法可以使得像你舉例的那種改動不可執行(例如re.M不再是一個數而是一個隨機密鑰,在載入模組時產生,具體辨認通過模組內隱藏的函數來執行,而不直接暴露參數本身)。只不過真的沒什麼必要。熟悉Python開發哲學的人會質問你不清楚後果為什麼要修改別的模組的全域變數?
要是想弄個不能被修改的常量對象也是沒問題的,簡單地利用元組的 immutable 特性即可:
from collections import namedtupledef const(**kwargs): ConstType = namedtuple("Constant", kwargs.keys()) return ConstType(**kwargs) const1 = const( name="test", value=123,)print const1.name # testconst1.name = "xxxx" # raise AttributeError
別作死…………
比如
True, False = False, True
全域變數可以有,但是如果濫用就不好了。考慮你問題的規模,小指令碼還好說,如果依賴複雜,大量依賴全域變數,我覺得設計本身可能就有問題。
建議將全域變數作為一個類的屬性,內部用單底線來限制外部調用,然後用@property將變數封裝成唯讀屬性。坑還是很多。。抖個機靈。
在c++裡這麼定義一下的話……
#DEFINE true false是。
也許是故意的。感覺python是提供了足夠的便捷,加入常量就如同加入資料類型一樣,更多的檢查本質上是為了規避編程者本身的問題,讓你少犯錯,在程式運行之前。為了足夠靈活,很多編譯型語言的特性拿掉,這些約束就落在了程式員身上,這未嘗不是件好事。總之,我清楚我在幹嘛,so,我才不會改第三方模組全域變數,也不會True=0,如果我真有這樣的需求…很感謝python提供了我這個許可權。 這個問題,完美的回答還是等什麼時候guido也用知乎了,邀請他回答下,哈哈,知乎願景。