1. 程式人生 > >【Python】python動態類型

【Python】python動態類型

引用變量 區分 如何工作 回收 new images 如何 空間 簡單的

在python中,省去了變量聲明的過程,在引用變量時,往往一個簡單的賦值語句就同時完成了,聲明變量類型,變量定義和關聯的過程,那麽python的變量到底是怎樣完成定義的呢?

動態類型

  python使用動態類型和他提供的多態性來提供python語言的簡潔靈活的基礎。在python中我們是不會聲明所使用對象的確切類型的。所謂的python動態類型,就是在程序運行的過程中自動決定對象的類型。

對象、變量和引用

  當我們在賦值一個變量時,在python中其實自動做了很多事情。

  1.創建變量:當代碼第一次賦值給一個變量時就創建了這個變量,在之後的賦值過程關聯值,python在代碼運行之前先檢驗變量名,可以當成是最初的賦值創建變量。

  2.變量聲明:python中類型只存在於對象中,而不是變量,變量是通用的,他只是在程序的某一段時間引用了某種類型的對象而已,比如定義a =1 ,a = ‘a‘,一開始定義了變量a為指向了整型的對象,然後變量又指向了字符串類型的變量,可見,變量是不固定的類型。

  3.變量使用:變量出現在表達式中就會馬上被對象所取代,無論對象是什麽內類型,變量在使用前必須要先定義。

  值得註意的是,變量必須在初始化名字之後才能更新他們,比如計數器初始化為0,然後才能增加他。

  也就是說,當我們給變量賦值的時候,比如a=3,python執行三個不同操作去完成賦值。

  1.創建一個對象代表3,

  2.如果程序中沒有變量a,則創建他。

  3.將變量與對象3連接起來。

  變量與對象是連接關系,它們存儲在內存的不同位置,如果有列表嵌套這樣大的對象,對象還連接到它包含的對象。這種從變量到對象的連接稱為引用。

  技術分享

  變量的引用以內存中的指針形式實現。一旦變量被使用,那麽python自動跟變量的對象連接。具體來說:

  1.變量是系統表的元素,他指向對象存放的地址空間。

  2.對象是分配的一塊內存,地址可被連接,有足夠大空間代表對象的值,

  3.引用的過程自動完成變量指向對象地址的過程,即從變量到對象的指針。

  對象的垃圾回收

  每個對象都有兩個標準頭部信息,一個是類型標誌符,用於標記對象類型,另一個是引用計數器,用來決定是不是可回收對象。很顯然,在python中只有對象才有類別區分,變量不過是引用了對象,變量並不具有類別區分,他只是在特定時間引用某個特定對象。

  對於引用計數器的使用,則關聯到python的垃圾回收機制,當當一個變量名賦予了一個新的對象,那麽之前舊的對象占用的地址空間就會被回收。舊對象的空間自動放入內存空間池,等待後來的對象使用。

  計數器在垃圾回收的過程中有事如何工作的呢?計數器記錄的是當前指向對象的引用數目,如果在某時刻計數器設置為0,則表示未被引用,name這個對象的內存空間就會收回。

  對象的垃圾回收有著很大的意義,這使得我們在python中任意使用對象而且不需要考慮釋放空間,省去了C與C++中大量的基礎代碼。

  共享引用(深淺拷貝的緣由)

  當一個變量使用多個對象時,舊的對象會被垃圾收回,那麽變量共享變量的對象有事一種什麽樣的類型呢?

a=‘hello world’
b=a
print(b)
運行結果:
hello world

  值得一提的是,這裏b變量引用的a作為值,根據python中賦值是以對象來完成的,所以b引用的應該是a變量指向的對象地址的值,故可以判斷,改變a指向的對象並不會影響b的值。

a=‘hello world’
b=a
a=‘new hello world‘
print(a)
print(b)
運行結果:
new hello world
hello world

  技術分享

  python中變量總是一個指定對象的指針,而不是能夠改變內存區域的標簽,即給一個變量賦新的值,不是替換一個對象原始值,而是創建一個新得對象供變量引用。

  當然這條只限於對象的類型不可改變,如果引用對象是像列表一樣可供修改的對象那結果如何呢?

a=[1,2,3]
b=a
a.append(4)
print(a)
print(b)
運行結果:
[1, 2, 3, 4]
[1, 2, 3, 4]

  結果很顯然,對於可變類型對象,變量不會創建一個顯得對象,而是沿用之前的對象,即使對象已經被改變了。可以簡單的理解為,兩個對象同時指向了一個列表的內存地址,而列表又映射了裏面各元素的內存地址,變量的共享並不關註列表的改變,他們只關心列表的內存空間是否改變,所以,可變對象在引用時自身可以改變,所以不需要創建新的對象,所以共享對象會隨之前對象的變化而變化。

  這其實是我們不希望看到的。我們可以使用拷貝對象創建引用:

a=[1,2,3]
b=a[:]
a.append(4)
print(a)
print(b)
運行結果:
[1, 2, 3, 4]
[1, 2, 3]

  這種方法並不適用於不可索引但是可變的字典與集合,所以python的copy模塊用於變量引用:

import copy
a=[1,2,3,[1,2]]
b=copy.copy(a)
c=copy.deepcopy(a)
d=a
a.append(4)
a[3][0]=5
print(a)
print(b)
print(c)
print(d)
運行結果:
[1, 2, 3, [5, 2], 4]
[1, 2, 3, [5, 2]]
[1, 2, 3, [1, 2]]
[1, 2, 3, [5, 2], 4]

共享引用的補充

  其實是關於垃圾回收的一點補充,對於一些小的整數或字符串,並不像我們說的那樣計數器標記為0就被收回。這和python的緩存機制有關。對於一般的對象,python適用於垃圾收回。

a=[1,2,3]
b=[1,2,3]
c=a
print(a == c)
print(a == b)
print(a is c)
print(a is b)
運行結果:
True
True
True
False

  對於小的整數與字符串則不同:

a=111
b=111
c=a
print(a == c)
print(a == b)
print(a is c)
print(a is b)
運行結果:
True
True
True
True

  在python中,任何東西都是在賦值與引用中工作的,對於理解python動態類型,在以後的工作與學習時是有很大幫助的,這是python唯一的賦值模型,所以準確的理解與應用十分有必要。不對類型作約束,這使得python代碼極為靈活,高效,並且省去了大量的代碼,極為簡潔,所以python是這樣一門有藝術的編程。

【Python】python動態類型