PyTips 0x0c - Python 知之深淺

項目地址:https://git.io/pytipspython

Python 中的對象分爲兩種:可變對象(mutable)和不可變對象(immutable)。不可變對象包括int,float,long,str,tuple等,可變對象包括list,set,dict等。在 Python 中,賦值(assignment, =)的過程僅僅是:git

  1. 建立一個(某個值的)對象;github

  2. 將變量名指向(引用)這個對象。閉包

這就像 C 語言中指針的概念,只不過更靈活地是 Python 中的變量隨時能夠指向其它對象(不分類型),其它變量也能夠指向這一對象。若是這一對象是可變的,那麼對其中一個引用變量的改變會影響其它變量:app

lst = [1, 2, 3]
s = lst
s.pop()
print(lst)

d = {'a': 0}
e = d
e['b'] = 1
print(d)
[1, 2]
{'b': 1, 'a': 0}

若是你不是刻意想要這樣作(實際也不多會要這樣操做),那麼就可能致使一些意想不到的錯誤(尤爲是在傳遞參數給函數的時候)。爲了解決這一麻煩,最簡單的方法就是不直接變量指向現有的對象,而是生成一份新的 copy 賦值給新的變量,有不少種語法能夠實現:函數

lst = [1,2,3]

llst = [lst,
        lst[:],
        lst.copy(),
        [*lst]] # invalid in 2.7
for i, v in enumerate(llst):
    v.append("#{}".format(i))
print(lst)

d = {"a": 0}
dd = [d,
      d.copy(),
      {**d}] # invalid in 2.7
for i, v in enumerate(dd):
    v['dd'] = "#{}".format(i)
print(d)
[1, 2, 3, '#0']
{'dd': '#0', 'a': 0}

deep vs shallow

上面給出的這些 copy 的例子比較簡單,都沒有嵌套的狀況出現,若是這裏的可變對象中還包含其它可變對象,結果會怎樣呢:學習

lst = [0, 1, [2, 3]]

llst = [lst,
        lst[:],
        lst.copy(),
        [*lst]]
for i, v in enumerate(llst):
    v[2].append("#{}".format(i))
print(lst)

d = {"a": {"b": [0]}}
dd = [d,
      d.copy(),
      {**d}]
for i, v in enumerate(dd):
    v['a']['b'].append("#{}".format(i))
print(d)
[0, 1, [2, 3, '#0', '#1', '#2', '#3']]
{'a': {'b': [0, '#0', '#1', '#2']}}

這些 copy 的方法稱爲淺拷貝(shallow copy),它相比直接賦值更進了一步生成了新的對象,可是對於嵌套的對象仍然採用了賦值的方法來建立;若是要再進一步,則須要深拷貝(deep copy),由標準庫 copy 提供:spa

from copy import deepcopy

lst = [0, 1, [2, 3]]
lst2 = deepcopy(lst)
lst2[2].append(4)
print(lst2)
print(lst)

d = {"a": {"b": [0]}}
d2 = deepcopy(d)
d2["a"]["b"].append(1)
print(d2)
print(d)
[0, 1, [2, 3, 4]]
[0, 1, [2, 3]]
{'a': {'b': [0, 1]}}
{'a': {'b': [0]}}

清楚了賦值(引用)、copy 仍是 deepcopy 之間的區別才能更好地避免意想不到的錯誤,一樣也能夠利用它們的特性去實現一些 little tricks,例如咱們在 0x04 閉包與做用域 中利用可變對象的特性實現 nonlocal 的功能。關於可變對象的引用、傳遞等既是 Python 的基本屬性,同時又由於隱藏在背後的「暗箱操做」而容易引發誤解,想要深刻了解能夠進一步閱讀參考連接的文章,我也會在後面的文章中繼續一邊學習、一邊補充更多這方面的知識。.net


歡迎關注公衆號 PyHub!指針

歡迎關注公衆號 PyHub!

參考

  1. python基礎(5):深刻理解 python 中的賦值、引用、拷貝、做用域

相關文章
相關標籤/搜索