python模組importlib使用/上下文管理器/深拷貝與淺拷貝
一:importlib模組
1,動態匯入模組,即根據字串形式的路徑匯入模組
import importlib
path = "settings.Foo"
m,c= path.rsplit(".",1)
module = importlib.import_module(m)
cls = getattr(module,c)
for key in dir(cls):
if key.isupper():
print(key,getattr(cls,key))
2,模組引入檢查,即檢查並觀察一個模組是否可以引入
import importlib.util import importlib def check_module(module_name): module_spec = importlib.util.find_spec(module_name) if module_spec is None: print("Module :{} not found".format(module_name)) return None else: print("Module:{} can be imported!".format(module_name)) return module_spec def import_module_from_spec(module_spec): module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) return module if __name__ == "__main__": module_spec = check_module("collections") if (module_spec): module = import_module_from_spec(module_spec) print(dir(module))
二:上下文管理器
上下文管理器規定了某個物件的使用範圍,當進入或者離開了使用範圍,都會有相應的一些呼叫,比如程式碼塊開始時執行一些準備,程式碼塊結束時結束一些操作。它更多的是用於資源的分配和釋放上,即在開始時分配資源,結束時釋放一些資源。比如在執行資料庫查詢時要建立連線,查詢結束後要釋放連線;寫檔案時要先開啟檔案,寫結束後,要關閉檔案等等。還有,就是資源的加鎖和解鎖,比如在使用多執行緒時,可能會用到加鎖和解鎖。
對於上下文管理器的使用,最常見的是使用with語句,with語句可構建資源的分配與釋放的語法糖。
要實現一個自定義的上下文管理器,肯定要實現兩個方法,一是進入物件範圍時的準備工作,二是離開物件範圍時的結束工作。
Python提供了兩個類的方法分別實現上述功能:
__enter__進入物件範圍時(一般程式碼塊開始)被呼叫;
__exit__離開物件範圍時(程式碼塊結束)被呼叫;
因此,一個Python類,只要實現了上述兩種方法,就可以說是一個上下文管理器。
三:深拷貝與淺拷貝
為了讓一個物件發生改變時不對原物件產生副作用,此時,需要一份這個物件的拷貝,python 提供了 copy 機制來完成這樣的任務,對應的模組是 copy。在 copy 模組中,有 copy 函式可以完成淺拷貝,有 deepcopy 函式可以完成深拷貝。
在 python 中,標識一個物件唯一身份的是:物件的id(記憶體地址),物件型別,物件值,而淺拷貝就是建立一個具有相同型別,相同值但不同id的新物件。
對可變物件而言,物件的值一樣可能包含有對其他物件的引用,淺拷貝產生的新物件,雖然具有完全不同的id,但是其值若包含可變物件,這些物件和原始物件中的值包含同樣的引用。
可見淺拷貝產生的新物件中可變物件的值在發生改變時會對原物件的值產生副作用,因為這些值是同一個引用。
淺拷貝僅僅對物件自身建立了一份拷貝,而沒有在進一步處理物件中包含的值。因此使用淺拷貝的典型使用場景是:物件自身發生改變的同時需要保持物件中的值完全相同,比如 list 排序。
深拷貝不僅僅拷貝了原始物件自身,也對其包含的值進行拷貝,它會遞迴的查詢物件中包含的其他物件的引用,來完成更深層次拷貝。因此,深拷貝產生的副本可以隨意修改而不需要擔心會引起原始值的改變。
對不可變型別,如字串,深拷貝與淺拷貝得到的id值與原值一樣,即引用的是同一個值;
對可變型別,如列表,深拷貝與淺拷貝得到的id值均與原值不一樣。
import copy
a = [[1,2,3],4,5,6,7]
b = copy.copy(a)
print(id(a),id(b)) # 2413605880456 2413605881736
b[0][0]=0
print(a,b) # [[0, 2, 3], 4, 5, 6, 7] [[0, 2, 3], 4, 5, 6, 7]
c = copy.deepcopy(a)
c[0][0]=9
print(a,c) # [[0, 2, 3], 4, 5, 6, 7] [[9, 2, 3], 4, 5, 6, 7]
自定義拷貝機制:
使用 _copy_ 和 __deepcopy__ 可以完成對一個物件拷貝的定製。