動態類型

變量,對象和引用python

變量在賦值的時候建立,它能夠引用任何類型的對象,而且必須在引用以前賦值。緩存

a = 3

全部賦值操做有三個步驟:函數

  1. 建立一個對象來表明值3
  2. 建立一個變量a,若是它尚未建立
  3. 將變量與新的對象3相鏈接

在運行a=3後,變量a變成對象3的一個引用,在內部,變量其實是到對象內存空間的一個指針。spa

類型屬於對象,而不是變量指針

a = 3
a = 'spam'
a = 1.23

變量名沒有類型,咱們只是把a修改成不一樣的對象的引用。所以,沒有改變a的類型,而是讓變量引用了不一樣類型的對象。code

每一個對象都包含了一個頭部信息,其中標記了這個對象的類型。對象

對象的垃圾回收blog

每當一個變量名被賦予了一個新的對象,以前那個對象佔用的空間就會被回收。這種技術叫作垃圾回收。內存

x = 42
x = 'shrubbery'
x = 3.1415
x = [1, 2, 3]

在內部,python在對象中保持了一個計數器,計數器記錄了當前指向該對象的引用的數目。一旦這個計數器被設置爲零,這個對象的內存空間就會自動回收。字符串

共享引用

a = 3
b = a

a和b引用了相同的對象,指向了相同的內存空間。多個變量引用同一個對象,這叫共享引用。

a = 3
b = a
a = 'spam'

這時候,b仍然引用原來的對象3。

a = 3
b = a
a = a + 2

a會賦值爲一個徹底不一樣的對象,而不會影響到b。b仍是3對象。

共享引用和在原處修改

對於支持在遠處修改的對象,共享引用時須要當心,由於對一個變量名的修改會影響其餘變量。

L1 = [2, 3, 4]
L2 = L1
L1[0] = 24

L1
#[24, 3, 4]
L2
#[24, 3, 4]

列表對象內的元素的遠處修改會印象程序其餘部分。若是不想要這樣的現象發生,須要python拷貝對象,而不是建立引用。拷貝列表能夠用內置列表函數,或者標準庫copy模塊,或者從頭至尾的分片。

L1 = [2, 3, 4]
L2 = L1[:]
L1[0] = 24

L1
#[24, 3, 4]
L2
#[2, 3, 4]

共享引用和相等

x = 42
x = 'shrubbery'

由於python會緩存而且複用小的整數和小的字符串,這裏的對象42也許並不會回收,它可能會保存在一個系統表中,等待下一次代碼生成一個42來重複利用。

python中有兩種辦法檢查是否相等。看共享引用的例子:

L = [1, 2, 3]
M = L

L == M
#True

L is M
#True

==操做符檢查值是否相等,is操做符,檢查對象的同一性,若是兩個變量指向同一個對象,那麼會返回True。

實際上,is比較實現引用的指針,因此這是一種檢查共享引用的方法。若是變量名的引用值相等,可是是不一樣的對象,它的返回值會是False。

L = [1, 2, 3]
M = [1, 2, 3]

L == M
#True

L is M
#False

但當咱們對小的數字作一樣的操做:

x = 42
y = 42

x == y
#True

x is y
#True

由於小的數字和字符串被緩存複用了,因此is告訴咱們它們引用的使用一個對象。

你能夠向python查詢一個對象引用的次數:在sys模塊中的getrefcount函數會返回對象的引用次數。例如,在IDLE GUI中查詢整數對象1時,會返回有837次引用。

import sys
sys.getrefcount(1)
#837
相關文章
相關標籤/搜索