傳參時傳遞可變物件,實際上傳的是指向記憶體地址的指標/參考
這個標題是我的結論,也是我在做專案程序查到的,學過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)回傳的是{},是一個不可變物件
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/271992.html
標籤:python
