詳解python函數(shù)傳參傳遞dict/list/set等類型的問題
傳參時(shí)傳遞可變對(duì)象,實(shí)際上傳的是指向內(nèi)存地址的指針/引用
這個(gè)標(biāo)題是我的結(jié)論,也是我在做項(xiàng)目過程查到的。學(xué)過C的都知道,函數(shù)傳參可以傳值,也可以傳指針。指針的好處此處不再贅述。
先上代碼看看效果:
def trans(var): return var source = {1: 1} dist = trans(source) source[2] = 2 print(source) print(dist)
運(yùn)行結(jié)果:
{1: 1, 2:2}
{1: 1, 2:2}
可以看到改變了source時(shí),dist也跟著改變了。原因就是source是可變對(duì)象,傳遞參數(shù)時(shí),傳的是其引用(C的指針)。dist和source都指向了同一片內(nèi)存空間。在運(yùn)行source[2] = 2時(shí),是對(duì)內(nèi)存空間的數(shù)據(jù)的變更,所以dist也跟著變化。
有什么作用呢?場(chǎng)景應(yīng)該很多,不過本人資歷尚淺,想不到典型場(chǎng)景,就拿自己的項(xiàng)目舉例。
項(xiàng)目中我定義了一個(gè)類,這個(gè)類用來讀寫配置,預(yù)存一些json配置,客戶端可以讀取配置,當(dāng)預(yù)存的配置不包含客戶端讀取的配置時(shí),就從設(shè)備讀取。
我需要這個(gè)類實(shí)例化出多個(gè)對(duì)象,對(duì)應(yīng)多個(gè)客戶端。但我希望預(yù)存的配置可以是公共的,這樣對(duì)于陌生配置,不用所有的客戶端請(qǐng)求時(shí),都需要從設(shè)備讀取。
一開始我是這么寫的:
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從設(shè)備獲取配置,假如賦值給了value dataset[key] = value return value def other_func(self): # 其他函數(shù),跟device_url有關(guān) pass
而后來我需要多份公共配置,甚至要達(dá)到1000份以上,顯然全局變量并不能很好滿足。因?yàn)橐灿脙?nèi)存,所以我傳遞可變對(duì)象,把代碼改成了這樣:
class Config(object): def __init__(self, dataset, device_url): # 傳遞可變對(duì)象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從設(shè)備獲取配置,假如賦值給了value self.dataset[key] = value # 可變對(duì)象dataset賦值,其他實(shí)例化的dataset屬性值也會(huì)變化 return value def other_func(self): # 其他函數(shù),跟device_url有關(guān) pass
列表、字典、集合不一定是可變對(duì)象
網(wǎng)上有一堆資料說列表、字典、集合是可變對(duì)象,這句話不完全正確。{} [] set((, ))常量不是可變對(duì)象。
上述的Config類,如果實(shí)例化時(shí)傳遞{},就不能共享配置。
config1 = Config({}) config2 = Config({}) config1.dataset[1] = 1 print(repr(config1.dataset)) print(repr(config2,dataset))
上述運(yùn)行結(jié)果是
'{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))
運(yùn)行結(jié)果就會(huì)變成:
'{1: 1}'
'{1: 1}'
share_var是可變對(duì)象,然而{}是不可變對(duì)象,雖然share_var和{}的值一樣。
要往更深層次地理解,就需要理解python的命名空間了。
傳參和傳遞可變對(duì)象參數(shù)需要注意的事情
- 如果不是要傳引用/指針,去操作對(duì)應(yīng)的內(nèi)存空間,則傳參時(shí)注意不要傳字典、列表、集合、類或類的實(shí)例化對(duì)象等類型
- 傳遞可變對(duì)象參數(shù)時(shí),注意不要傳常量{} [] set((, )),最好是在傳參前付給一個(gè)變量,傳參時(shí)傳這個(gè)變量。
懂了原理可能不至于直接傳常量,但是有可能出現(xiàn)下面這種情況:
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)返回的是{},是一個(gè)不可變對(duì)象
到此這篇關(guān)于詳解python函數(shù)傳參傳遞dict/list/set等類型的問題的文章就介紹到這了,更多相關(guān)python函數(shù)傳參傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python構(gòu)造自定義方法來美化字典結(jié)構(gòu)輸出的示例
這篇文章主要介紹了用Python構(gòu)造自定義方法來美化字典結(jié)構(gòu)輸出的示例,原理就是利用遞歸法來拼接字符串,需要的朋友可以參考下2016-06-06Python中.py程序在CMD控制臺(tái)以指定虛擬環(huán)境運(yùn)行
本文主要介紹了Python中.py程序在CMD控制臺(tái)以指定虛擬環(huán)境運(yùn)行,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Python查找算法之折半查找算法的實(shí)現(xiàn)
這篇文章主要介紹了Python查找算法之折半查找算法的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04python學(xué)生信息管理系統(tǒng)實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了python學(xué)生信息管理系統(tǒng)的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06python asyncio 協(xié)程庫(kù)的使用
這篇文章主要介紹了python asyncio 協(xié)程庫(kù)的使用,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2021-01-01python方法生成txt標(biāo)簽文件的實(shí)例代碼
今天小編就為大家分享一篇python方法生成txt標(biāo)簽文件的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-05-05python實(shí)現(xiàn)2014火車票查詢代碼分享
學(xué)習(xí)習(xí)PYTHON開始,實(shí)現(xiàn)了一個(gè)火車票查詢的小功能,希望能幫大家買到回家的票2014-01-01Python中統(tǒng)計(jì)函數(shù)運(yùn)行耗時(shí)的方法
這篇文章主要介紹了Python中統(tǒng)計(jì)函數(shù)運(yùn)行耗時(shí)的方法,涉及Python時(shí)間操作的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-05-05