Python中的對象引用、可變性和垃圾回收

導語:本文章記錄了本人在學習Python基礎之面向對象篇的重點知識及我的心得,打算入門Python的朋友們能夠來一塊兒學習並交流。

本文重點:python

一、明確變量保存的是引用這一本質;
二、熟悉對象引用的基礎知識;
三、掌握深複製和淺複製;
四、熟悉函數傳參引用時潛在的麻煩並避免。

1、對象引用基礎知識

  1. 變量:是標註而不是容器。對引用式變量而言,是把變量分配給對象,反過來理解則不合理。
  2. 別名:同一個對象的不一樣標註就是別名,別名指向同一對象。
  3. 標識:能夠把標識理解爲對象在內存中的地址。每一個變量都有標識、類型和值。對象一旦建立,它的標識毫不會變。is運算符比較兩個對象的標識;id()函數返回對象標識的整數表示,即對象的內存地址。
  4. 相等性:用==運算符比較兩個對象的值是否相等。注意a==b是語法糖,等同於a.__eq__(b)。
  5. ==和is的選擇:咱們關注值的頻率比標識要高。

當比較變量和單例值的時候應該用is。例如:X is None 或 X is not None。算法

is運算符比==要快,由於is不能重載。數據結構

2、可變性

一、元組的相對不可變性:

指tuple數據結構的物理內容(即保存的引用)不可變。也就是說元組中不可變的是元素的標識,但元組的值會隨着引用的可變對象變化而變化。
tuple,list,dict,set保存的是對象的引用,而str,byte,array.array保存的是對象的值(字符,字節,數字)。函數

二、淺複製與深複製

淺複製:當複製tuple,list,dict,set時,副本之間共享內部對象的引用。copy.copy()
深複製:當複製tuple,list,dict,set時,副本之間不共享內部對象的引用。copy.deepcopy()學習

eg:淺複製小例子code

list1=[1,(55,66),[7,8,9]]
list2=list(list1)#構建副本默認爲淺複製
list2[1]+=(77,88)#對元組進行+=運算會解綁list2[1],並與右端運算後的值之間從新綁定起來。
list2[2]+=[10]#對列表進行iadd運算會就地修改列表,不會發生從新綁定。
list2[0]*=3
list1[2].pop(0)
print(list1)
print(list2)
#輸出:
[1, (55, 66), [8, 9, 10]]
[3, (55, 66, 77, 88), [8, 9, 10]]

分析:list2是list1的副本,咱們對list2的三個元素均做了改動,但只有列表元素的改動影響到了list1。緣由在於list1和list2的第三個列表元素共享引用,所以影響也會同步;元組由於發生瞭解綁的運算因此影響未同步到list1;至於數值的影響不一樣步的緣由是由於淺複製針對str,byte,array.array這些對象直接將值從新保存到副本中來,不存在共享引用的內部邏輯。對象

深複製注意事項內存

  • 深複製處在循環引用的對象時,深複製算法會進入無限循環中。
  • 一些對象可能會引用不應複製的外部資源或單例值,這些對象的深複製的結果可能太深。

三、函數的參數做爲引用時:

Python惟一支持的參數傳遞模式是共享傳參。共享傳參指函數的各個形式參數得到實參中各個引用的副本,即函數內部的形參是實參的別名。資源

  • 函數可能會修改做爲參數傳入的可變對象。
    (1)這個行爲沒法避免,除非在本地建立副本,或者使用不可變對象。

    (2)所以在類中直接把參數賦值給實例變量以前必定要三思,由於這樣會爲參數對象建立別名,修改傳入參數指向的可變對象。字符串

eg:函數修改做爲參數傳入的全局變量

def f(a, b):
    a += b
    return a
a = [1, 2]
b = [3, 4]
f(a, b)
print(a, b)#輸出[1, 2, 3, 4], [3, 4],此時列表a已經發生變化。
t = (10, 20)
u = (30, 40)
f(t, u)
print(t, u)#輸出((10, 20), (30, 40)),此時元組t沒有發生變化。
  • 使用可變類型做爲函數參數的默認值有危險。
    緣由在於包含此類函數的類的實例在未指定初始值時會使用同一個可變默認值。當一個實例就地修改參數時會影響其餘實例對默認值的調用。

3、垃圾回收

一、垃圾回收的斷定規則:

  • 主要採用引用計數算法。
    在Python中每一個對象的引用都會有統計。當引用計數歸零時,對象就會當即銷燬。
  • 除了循環引用外沒有其餘引用,處在循環引用的對象都會被銷燬。

二、弱引用

  • 某些狀況下可能須要保存對象的引用,但不留存對象自己,此時能夠藉助弱引用實現。弱引用不會妨礙對象被當作垃圾回收。
  • 弱引用是一種低層機制,是weakref模塊中WeakValueDictionary、WeakKeyDictionary和WeakSet等有用的集合類,以及finalize函數的底層支持。
  • 弱引用的侷限性
    弱引用所指對象能夠是set,用戶自定義的類,list和dict的子類。不能夠是int、tuple的實例及子類,也不能夠是list實例或dict實例。

4、Python對不可變類型施加的把戲

一、使用一個元組來構造另外一個元組,獲得的實際上是同一個元組。

二、比較字符串或整數是否相等時,應該使用==而不是is。這是因爲Python解釋器內部駐留的特性所致使的。

相關文章
相關標籤/搜索