一種Python全局配置規范以及其魔改

      網友投稿 953 2022-05-30

      一、模塊 or global

      很多初學者有個誤區,就是在Python中需要配置一個全局的參數時,首先想到的是global關鍵字,而實際上global不是干這個事的,global的功能是在將局部作用域的變量聲明為全局的,這樣可以在局部修改全局的變量。

      但這種用法其實非常不好,按照函數式的規范而言,純函數的輸入應該只有輸入參數確定,不應該在執行過程中引用外部變量。并且,global也不是用來進行全局配置用的。

      在Python中,模塊是天然的單例,模塊會在項目初始化后執行一次,之后一般不重復執行,符合單例模式的特點。因此,利用模塊的這一特性,將整個工程文件中需要配置的選項都配置到一個模塊中,在需要用的模塊中通過import導入,才是Python中全局配置正確打開方式。

      雖然這種規范已經在江茍(Django)等開源框架中展示了無數遍,但“如何在Python中設置全局變量”這個問題仍然是Python社區的月經貼。

      通過模塊配置全局變量的試例如下,在configs.py中定義CONFIG_A和CONFIG_B。在user.py中用import導入。

      這個其實是Python中的基本操作了,本來是沒啥好講的,不過在這篇文章最后我展示了一種根據json配置的動態模塊,供大家參考。

      二、單例字典

      在講模塊之前,我想談談我嘗試過另一種方式,就是自定義單例字典,具體做法是這樣的。

      先繼承collections模塊中MutableMapping,并重寫相關接口。這是在Python中自定義數據類型的基本操作了,自定義完成后然后寫一個裝飾器將繼承的類轉化成單例的類。

      單例模式的寫法可以看Stackoverflow上關于單例模式的高票回答。

      我習慣采用第一種函數裝飾器的寫法:

      這種寫法非常好理解,用一個類變量instances保存該類生成的實例,每次類被調用的時候判斷一下這個類是否在instances字典里,如果不在著生成一個實例并放入instances字典。

      但這個寫法有個問題,裝飾后的返回的不是一個類,而是一個函數,雖然Python語法講究一切皆對象,但函數是享受不到類的諸如繼承之類的特性的。

      如果需要返回一個單例類的話需要用元類的寫法,或者第四種類裝飾器的寫法。當然,具體到這里而言,這個類是繼承了一個MutableMapping的,不能再繼承別的元類了,元類的寫法在這里不適用。

      三、單例字典的問題

      一種Python全局配置規范以及其魔改

      用單例字典做全局配置看著比模塊炫酷,其實并沒那么好用。原因是單例模式自身的一個弊病,違背了單一職責原則,這個在相關設計模式的教程里有講到。而且,字典在這一塊還有個弊病就是根本不知道需要用到的key是不是存在字典中。

      單例字典是我在項目初期引入,并在項目的迭代過程中給我造成最大困擾的一個東西,在開始時幾乎將所有的配置都寫入到這個字典中,然后在程序運行中這個字典又被分散在程序各處的各個實例修改,運行到后面根本不知道字典里有什么,字典里的某個內容是否被修改過。不過由于GIL,倒是不需要考慮鎖的問題,可能是唯一的一個幸事。

      在后期將這個龐大的字典進行重構,重構的過程按照下面的方式進行:

      1、將各個類中該字典的引用點,由各個方法收攏到init方法。

      不應該

      應該

      2、將各個引用點的名稱統一。

      不應該

      應該

      3、將子函數中直接引用單例字典的參數放到函數的參數列表中,由調用方獲取單例字典內容,由傳參的方法傳入被調用函數,這樣做是為了滿足函數式編程中純函數的原則。

      不應該這么用:

      應該這樣用

      4、將單一的單例字典分成多個單例字典,并將部分單例字典轉換成模塊,這個就不舉例了。

      四、動態模塊

      模塊的用法很簡單,在一個文件里配置好,直接import就行。需要注意的是引用的入口最好在同一個地方。

      不過模塊有個地方不好就是動態修改不方便,具體到項目中去就是,該項目通過工廠模式生成了一系列產品,每個產品所需的配置參數都不一樣。

      這里有個辦法就是每個產品都通過同一個模塊來配置,然后在初始化時根據以產品名稱命名的一個json文件修改模塊的參數。這樣就可以達到引用模塊的方式不變,但模塊的內容是根據json文件的內容來配置的。

      詳細的代碼見github,主要用來動態修改模塊的語句如下:

      其實就是通過setattr這個常用的給對象動態的添加功能的函數,d.tiems()是一個從json文件中讀取的字典對象。

      五、動態模塊的優勢

      現在,一個配置模塊的方案就成了導入configs模塊,調用update_config_by_name函數,即動態修改函數,并按照相應的json文件修改模塊的值。

      相對于在每個類初始化時直接調用json配置變量這種方案是有好處的,定義了configs模塊有助于代碼的靜態檢查,形成了一種像C語言中.h文件和.c文件的關系,在頭文件中定義相關的變量,在.c文件中實現或使用。這里就成了在configs模塊中定義變量,變量的值由json文件確定,然后在其他模塊中通過import實現,并且這個東西是全局共享的。當然,這個全局的意思指的是整個解釋器。

      這段代碼還是有個坑,一般出現在單元測試中,來看兩段代碼:

      在單元測試中由于deepcopy的問題,根據導入的層級不一樣,CONFIG_X的值也發生了不一樣的改變,這是個還在研究的bug。

      開發者 編程語言 Python

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Spark性能優化 (4) | JVM 調優
      下一篇:Jetty9部署多個項目及虛擬主機配置的方法
      相關文章
      亚洲电影在线播放| 亚洲av无码专区国产乱码在线观看| 亚洲国产精品婷婷久久| AV在线亚洲男人的天堂| 亚洲国产精品国产自在在线| 无码天堂va亚洲va在线va| 久久久亚洲精华液精华液精华液| 亚洲成在人线aⅴ免费毛片| 亚洲日本一线产区和二线产区对比| 亚洲国产精品综合久久20| 亚洲va精品中文字幕| 亚洲人成人77777在线播放| 亚洲一区二区三区久久| 亚洲18在线天美| 色在线亚洲视频www| 国产精品亚洲精品| 亚洲人成网站999久久久综合| 亚洲午夜福利在线视频| 亚洲欧美国产日韩av野草社区| 亚洲乱码av中文一区二区| 亚洲AV无码专区在线电影成人| 亚洲AV无码成人网站在线观看| 豆国产96在线|亚洲| 亚洲精品亚洲人成在线观看下载 | 亚洲麻豆精品国偷自产在线91| 亚洲成AV人网址| 国产亚洲精aa成人网站| 日本亚洲成高清一区二区三区| 香蕉蕉亚亚洲aav综合| 亚洲色偷偷偷网站色偷一区| 亚洲免费视频网址| 亚洲中文字幕无码中文| 国产偷国产偷亚洲高清人| 亚洲最大av无码网址| 亚洲AV无码码潮喷在线观看| 亚洲男人的天堂在线播放| 亚洲校园春色小说| 亚洲熟妇丰满xxxxx| 亚洲精品成人在线| 国产成人亚洲精品青草天美| 久久水蜜桃亚洲av无码精品麻豆|