新聞中心
一、模塊 or global

成都創(chuàng)新互聯(lián)公司服務(wù)項目包括定邊網(wǎng)站建設(shè)、定邊網(wǎng)站制作、定邊網(wǎng)頁制作以及定邊網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,定邊網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到定邊省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
很多初學(xué)者有個誤區(qū),就是在Python中需要配置一個全局的參數(shù)時,首先想到的是global關(guān)鍵字,而實際上global不是干這個事的,global的功能是在將局部作用域的變量聲明為全局的,這樣可以在局部修改全局的變量。
但這種用法其實非常不好,按照函數(shù)式的規(guī)范而言,純函數(shù)的輸入應(yīng)該只有輸入?yún)?shù)確定,不應(yīng)該在執(zhí)行過程中引用外部變量。并且,global也不是用來進行全局配置用的。
在Python中,模塊是天然的單例,模塊會在項目初始化后執(zhí)行一次,之后一般不重復(fù)執(zhí)行,符合單例模式的特點。因此,利用模塊的這一特性,將整個工程文件中需要配置的選項都配置到一個模塊中,在需要用的模塊中通過import導(dǎo)入,才是Python中全局配置正確打開方式。
雖然這種規(guī)范已經(jīng)在江茍(Django)等開源框架中展示了無數(shù)遍,但“如何在Python中設(shè)置全局變量”這個問題仍然是Python社區(qū)的月經(jīng)貼。
通過模塊配置全局變量的試例如下,在configs.py中定義CONFIG_A和CONFIG_B。在user.py中用import導(dǎo)入。
這個其實是Python中的基本操作了,本來是沒啥好講的,不過在這篇文章最后我展示了一種根據(jù)json配置的動態(tài)模塊,供大家參考。
二、單例字典
在講模塊之前,我想談?wù)勎覈L試過另一種方式,就是自定義單例字典,具體做法是這樣的。
先繼承collections模塊中MutableMapping,并重寫相關(guān)接口。這是在Python中自定義數(shù)據(jù)類型的基本操作了,自定義完成后然后寫一個裝飾器將繼承的類轉(zhuǎn)化成單例的類。
單例模式的寫法可以看Stackoverflow上關(guān)于單例模式的高票回答。
我習(xí)慣采用第一種函數(shù)裝飾器的寫法:
這種寫法非常好理解,用一個類變量instances保存該類生成的實例,每次類被調(diào)用的時候判斷一下這個類是否在instances字典里,如果不在著生成一個實例并放入instances字典。
但這個寫法有個問題,裝飾后的返回的不是一個類,而是一個函數(shù),雖然Python語法講究一切皆對象,但函數(shù)是享受不到類的諸如繼承之類的特性的。
如果需要返回一個單例類的話需要用元類的寫法,或者第四種類裝飾器的寫法。當然,具體到這里而言,這個類是繼承了一個MutableMapping的,不能再繼承別的元類了,元類的寫法在這里不適用。
三、單例字典的問題
用單例字典做全局配置看著比模塊炫酷,其實并沒那么好用。原因是單例模式自身的一個弊病,違背了單一職責(zé)原則,這個在相關(guān)設(shè)計模式的教程里有講到。而且,字典在這一塊還有個弊病就是根本不知道需要用到的key是不是存在字典中。
單例字典是我在項目初期引入,并在項目的迭代過程中給我造成最大困擾的一個東西,在開始時幾乎將所有的配置都寫入到這個字典中,然后在程序運行中這個字典又被分散在程序各處的各個實例修改,運行到后面根本不知道字典里有什么,字典里的某個內(nèi)容是否被修改過。不過由于GIL,倒是不需要考慮鎖的問題,可能是唯一的一個幸事。
在后期將這個龐大的字典進行重構(gòu),重構(gòu)的過程按照下面的方式進行:
1、將各個類中該字典的引用點,由各個方法收攏到init方法。
不應(yīng)該
應(yīng)該
2、將各個引用點的名稱統(tǒng)一。
不應(yīng)該
應(yīng)該
3、將子函數(shù)中直接引用單例字典的參數(shù)放到函數(shù)的參數(shù)列表中,由調(diào)用方獲取單例字典內(nèi)容,由傳參的方法傳入被調(diào)用函數(shù),這樣做是為了滿足函數(shù)式編程中純函數(shù)的原則。
不應(yīng)該這么用:
應(yīng)該這樣用
4、將單一的單例字典分成多個單例字典,并將部分單例字典轉(zhuǎn)換成模塊,這個就不舉例了。
四、動態(tài)模塊
模塊的用法很簡單,在一個文件里配置好,直接import就行。需要注意的是引用的入口最好在同一個地方。
不過模塊有個地方不好就是動態(tài)修改不方便,具體到項目中去就是,該項目通過工廠模式生成了一系列產(chǎn)品,每個產(chǎn)品所需的配置參數(shù)都不一樣。
這里有個辦法就是每個產(chǎn)品都通過同一個模塊來配置,然后在初始化時根據(jù)以產(chǎn)品名稱命名的一個json文件修改模塊的參數(shù)。這樣就可以達到引用模塊的方式不變,但模塊的內(nèi)容是根據(jù)json文件的內(nèi)容來配置的。
詳細的代碼見github,主要用來動態(tài)修改模塊的語句如下:
其實就是通過setattr這個常用的給對象動態(tài)的添加功能的函數(shù),d.tiems()是一個從json文件中讀取的字典對象。
五、動態(tài)模塊的優(yōu)勢
現(xiàn)在,一個配置模塊的方案就成了導(dǎo)入configs模塊,調(diào)用update_config_by_name函數(shù),即動態(tài)修改函數(shù),并按照相應(yīng)的json文件修改模塊的值。
相對于在每個類初始化時直接調(diào)用json配置變量這種方案是有好處的,定義了configs模塊有助于代碼的靜態(tài)檢查,形成了一種像C語言中.h文件和.c文件的關(guān)系,在頭文件中定義相關(guān)的變量,在.c文件中實現(xiàn)或使用。這里就成了在configs模塊中定義變量,變量的值由json文件確定,然后在其他模塊中通過import實現(xiàn),并且這個東西是全局共享的。當然,這個全局的意思指的是整個解釋器。
這段代碼還是有個坑,一般出現(xiàn)在單元測試中,來看兩段代碼:
在單元測試中由于deepcopy的問題,根據(jù)導(dǎo)入的層級不一樣,CONFIG_X的值也發(fā)生了不一樣的改變,這是個還在研究的bug。
網(wǎng)頁標題:一種Python全局配置規(guī)范以及其魔改
網(wǎng)頁網(wǎng)址:http://www.dlmjj.cn/article/dpopsep.html


咨詢
建站咨詢
