詳解python函數傳參傳遞dict/list/set等類型的問題
傳參時傳遞可變對象,實際上傳的是指向內存地址的指針/引用
這個標題是我的結論,也是我在做項目過程查到的。學過C的都知道,函數傳參可以傳值,也可以傳指針。指針的好處此處不再贅述。
先上代碼看看效果:
def trans(var): return var source = {1: 1} dist = trans(source) source[2] = 2 print(source) print(dist)
運行結果:
{1: 1, 2:2}
{1: 1, 2:2}
可以看到改變瞭source時,dist也跟著改變瞭。原因就是source是可變對象,傳遞參數時,傳的是其引用(C的指針)。dist和source都指向瞭同一片內存空間。在運行source[2] = 2時,是對內存空間的數據的變更,所以dist也跟著變化。
有什麼作用呢?場景應該很多,不過本人資歷尚淺,想不到典型場景,就拿自己的項目舉例。
項目中我定義瞭一個類,這個類用來讀寫配置,預存一些json配置,客戶端可以讀取配置,當預存的配置不包含客戶端讀取的配置時,就從設備讀取。
我需要這個類實例化出多個對象,對應多個客戶端。但我希望預存的配置可以是公共的,這樣對於陌生配置,不用所有的客戶端請求時,都需要從設備讀取。
一開始我是這麼寫的:
global dataset dataset = {} class Config(object): def __init__(self, device_url): self.device_url = device_url def get_config(self, key): global dataset if key in dataset: return dataset.get(key) else: # 通過device_url從設備獲取配置,假如賦值給瞭value dataset[key] = value return value def other_func(self): # 其他函數,跟device_url有關 pass
而後來我需要多份公共配置,甚至要達到1000份以上,顯然全局變量並不能很好滿足。因為要共用內存,所以我傳遞可變對象,把代碼改成瞭這樣:
class Config(object): def __init__(self, dataset, device_url): # 傳遞可變對象dataset self.dataset = dataset self.device_url = device_url def get_config(self, key): if key in self.dataset: return self.dataset.get(key) else: # 通過device_url從設備獲取配置,假如賦值給瞭value self.dataset[key] = value # 可變對象dataset賦值,其他實例化的dataset屬性值也會變化 return value def other_func(self): # 其他函數,跟device_url有關 pass
列表、字典、集合不一定是可變對象
網上有一堆資料說列表、字典、集合是可變對象,這句話不完全正確。{} [] set((, ))常量不是可變對象。
上述的Config類,如果實例化時傳遞{},就不能共享配置。
config1 = Config({}) config2 = Config({}) config1.dataset[1] = 1 print(repr(config1.dataset)) print(repr(config2,dataset))
上述運行結果是
‘{1: 1}’
‘None’
但如果是這樣
share_var = {} config1 = Config(share_var) config2 = Config(share_var) config1.dataset[1] = 1 print(repr(config1.dataset)) print(repr(config2,dataset))
運行結果就會變成:
‘{1: 1}’
‘{1: 1}’
share_var是可變對象,然而{}是不可變對象,雖然share_var和{}的值一樣。
要往更深層次地理解,就需要理解python的命名空間瞭。
傳參和傳遞可變對象參數需要註意的事情
- 如果不是要傳引用/指針,去操作對應的內存空間,則傳參時註意不要傳字典、列表、集合、類或類的實例化對象等類型
- 傳遞可變對象參數時,註意不要傳常量{} [] set((, )),最好是在傳參前付給一個變量,傳參時傳這個變量。
懂瞭原理可能不至於直接傳常量,但是有可能出現下面這種情況:
def func1(mutable_object, flag): if flag: return mutable_object else: return {} def func2(mutable_object): # something to do with mutable_object pass func2(func1(mutable_object, False)) # 此處func1(mutable_object, False)返回的是{},是一個不可變對象
到此這篇關於詳解python函數傳參傳遞dict/list/set等類型的問題的文章就介紹到這瞭,更多相關python函數傳參傳遞內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- None Found