python變數生命周期
Ⅰ 為什麼說python採用的是基於值的內存管理模式
先從較淺的層面來說,Python的內存管理機制可以從三個方面來講
(1)垃圾回收
(2)引用計數
(3)內存池機制
一、垃圾回收:
python不像C++,Java等語言一樣,他們可以不用事先聲明變數類型而直接對變數進行賦值。對Python語言來講,對象的類型和內存都是
在運行時確定的。這也是為什麼我們稱Python語言為動態類型的原因(這里我們把動態類型可以簡單的歸結為對變數內存地址的分配是在運行時自動判斷變數
類型並對變數進行賦值)。
二、引用計數:
Python採用了類似Windows內核對象一樣的方式來對內存進行管理。每一個對象,都維護這一個對指向該對對象的引用的計數。如圖所示(圖片來自Python核心編程)
x = 3.14
y = x
我們首先創建了一個對象3.14, 然後將這個浮點數對象的引用賦值給x,因為x是第一個引用,因此,這個浮點數對象的引用計數為1. 語句y =
x創建了一個指向同一個對象的引用別名y,我們發現,並沒有為Y創建一個新的對象,而是將Y也指向了x指向的浮點數對象,使其引用計數為2.
我們可以很容易就證明上述的觀點:
變數a 和 變數b的id一致(我們可以將id值想像為C中變數的指針).
我們援引另一個網址的圖片來說明問題:對於C語言來講,我們創建一個變數A時就會為為該變數申請一個內存空間,並將變數值
放入該空間中,當將該變數賦給另一變數B時會為B申請一個新的內存空間,並將變數值放入到B的內存空間中,這也是為什麼A和B的指針不一致的原因。如圖:
而Python的情況卻不一樣,實際上,Python的處理方式和Javascript有點類似,如圖所示,變數更像是附在對象上的標簽(和引用的
定義類似)。當變數被綁定在一個對象上的時候,該變數的引用計數就是1,(還有另外一些情況也會導致變數引用計數的增加),系統會自動維護這些標簽,並定
時掃描,當某標簽的引用計數變為0的時候,該對就會被回收。
三、內存池機制
Python的內存機制以金字塔行,-1,-2層主要有操作系統進行操作,
第0層是C中的malloc,free等內存分配和釋放函數進行操作;
第1層和第2層是內存池,有Python的介面函數PyMem_Malloc函數實現,當對象小於256K時有該層直接分配內存;
第3層是最上層,也就是我們對Python對象的直接操作;
在 C 中如果頻繁的調用 malloc 與 free 時,是會產生性能問題的.再加上頻繁的分配與釋放小塊的內存會產生內存碎片. Python 在這里主要乾的工作有:
如果請求分配的內存在1~256位元組之間就使用自己的內存管理系統,否則直接使用 malloc.
這里還是會調用 malloc 分配內存,但每次會分配一塊大小為256k的大塊內存.
經由內存池登記的內存到最後還是會回收到內存池,並不會調用 C 的 free
釋放掉.以便下次使用.對於簡單的Python對象,例如數值、字元串,元組(tuple不允許被更改)採用的是復制的方式(深拷貝?),也就是說當將另
一個變數B賦值給變數A時,雖然A和B的內存空間仍然相同,但當A的值發生變化時,會重新給A分配空間,A和B的地址變得不再相同;
而對於像字典(dict),列表(List)等,改變一個就會引起另一個的改變,也稱之為淺拷貝:
附錄:
引用計數增加
1.對象被創建:x=4
2.另外的別人被創建:y=x
3.被作為參數傳遞給函數:foo(x)
4.作為容器對象的一個元素:a=[1,x,』33』]
引用計數減少
1.一個本地引用離開了它的作用域。比如上面的foo(x)函數結束時,x指向的對象引用減1。
2.對象的別名被顯式的銷毀:del x ;或者del y
3.對象的一個別名被賦值給其他對象:x=789
4.對象從一個窗口對象中移除:myList.remove(x)
5.窗口對象本身被銷毀:del myList,或者窗口對象本身離開了作用域。
垃圾回收
1、當內存中有不再使用的部分時,垃圾收集器就會把他們清理掉。它會去檢查那些引用計數為0的對象,然後清除其在內存的空間。當然除了引用計數為0的會被清除,還有一種情況也會被垃圾收集器清掉:當兩個對象相互引用時,他們本身其他的引用已經為0了。
2、垃圾回收機制還有一個循環垃圾回收器, 確保釋放循環引用對象(a引用b, b引用a, 導致其引用計數永遠不為0)。
Ⅱ 軟體測試中,python中的 ==和 is 之間的區別
在Python中一切都是對象。
Python中對象包含的三個基本要素,分別是:id(身份標識)、type(數據類型)和value(值)。對象之間比較是否相等可以用==,也可以用is。
is和==都是對對象進行比較判斷作用的,但對對象比較判斷的內容並不相同。下面來看看具體區別在哪?
is比較的是兩個對象的id值是否相等,也就是比較兩個對象是否為同一個實例對象,是否指向同一個內存地址。
==比較的是兩個對象的內容是否相等,默認會調用對象的__eq__()方法。
以下代碼在Python3.5下測試通過。
==比較操作符和is同一性運算符區別
==是python標准操作符中的比較操作符,用來比較判斷兩個對象的value(值)是否相等。
代碼1:
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
>>> b == a
True
>>> b = a[:]
>>> b is a
False
>>> b == a
True
解釋一下為什麼?is也被叫做同一性運算符,也就是id是否相同。看下面代碼, a和b變數的id不同, 所以b==a是True, b is a 是False.
代碼2:
>>> id(a)
4364243328
>>>
>>> id(b)
4364202696
哪些情況下is和==結果是完全相同的?
代碼3:
>>> a = 256
>>> b = 256
>>> a is b
True
>>> a == b
True
>>>
>>> a = 1000
>>> b = 10**3
>>> a == b
True
>>> a is b
False
>>>
結論:數字類型不完全相同。
為什麼256時相同, 而1000時不同?
因為出於對性能的考慮,Python內部做了很多的優化工作,對於整數對象,Python把一些頻繁使用的整數對象緩存起來,保存到一個叫small_ints的鏈表中,在Python的整個生命周期內,任何需要引用這些整數對象的地方,都不再重新創建新的對象,而是直接引用緩存中的對象。Python把這些可能頻繁使用的整數對象規定在范圍[-5, 256]之間的小對象放在small_ints中,但凡是需要用些小整數時,就從這裡面取,不再去臨時創建新的對象。
代碼4:
>>> c = 'pythontab.com'
>>> d = 'pythontab.com'
>>> c is d
False
>>> c == d
True
>>> c = 'pythontabcom'
>>> d = 'pythontabcom'
>>> c is c
True
>>> c == d
True
結論:字元串類型不完全相同。這個和解釋器實現有關。
代碼5:
>>> a = (1,2,3) #a和b為元組類型
>>> b = (1,2,3)
>>> a is b
False
>>> a = [1,2,3] #a和b為list類型
>>> b = [1,2,3]
>>> a is b
False
>>> a = {'python':100,'com':1} #a和b為dict類型
>>> b = {'python':100,'com':1}
>>> a is b
False
>>> a = set([1,2,3])#a和b為set類型
>>> b = set([1,2,3])
>>> a is b
False
結論
當變數是數字、字元串、元組,列表,字典時,is和==都不相同, 不能互換使用!當比較值時,要使用==,比較是否是同一個內存地址時應該使用is。當然,開發中比較值的情況比較多。
Ⅲ Python其實很簡單 第五章 基本數據類型
編程的目的就是為了處理信息,信息則是由各種不同類型的數據表示的,對數據的進一步處理也會使信息更加豐富和有效。
5.1變數
前面已經提到過「變數」這屬語,下面再進一步解釋一下。
在程序運行時,必須把數據導入計算機的存儲單元中,但存儲單元的命名是用二進制數表示的,晦澀難懂。為了方便起見,可以給存儲單元起上一個通俗易懂的名字,即 變數名 。
變數的生命周期和程序的運行周期是相同的,一個程序運行解釋,所佔用的存儲空間也就隨之釋放,用變數名表示的數據所佔用的這個存儲單元也就空閑了。
變數名的命名規則:
由字母、數字、下劃線構成,必須由字母開頭。
不能包含-、*、?、#、、;、/、、@、%、$、空格等特殊字元。
最好使用有含義的英文單詞或漢語拼音。
最好採用小寫字母。
不能使用保留字(已被Python語言系統本身賦予特定意義的單詞)。Python的保留字如下表所示。
Python保留字列表
Python是區分大小寫的,雖然可以將一個英文單詞通過字母大小寫不同而作為不同變數的變數名,但從程序可讀性的角度看,的確不可取。
Python是一種動態類型的語言,變數的類型由變數的值決定。換而言之,給變數賦何種類型的值,變數就是該值的類型。給變數賦值可以通過賦值號(=)來實現。如:
>>> myvar=100
>>> type(myvar)
>>> myvar='tom'
>>> type(myvar)
在這個例子中,變數myvar首先賦值為100,顯而易見,100是個整數,通過type()這個函數檢測,變數myvar的類型為整數類型(int);接下來變數myvar賦值為『tom』,通過type()這個函數檢測,變數myvar的類型改變為字元串類型(str)。
不僅可以給一個變數賦值為常量,也可以賦值為另一個變數。如:
>>> a=100
>>> b=a
>>> b
100
在這個例子中,「b=a」的實際意義是,變數b和變數a指向同一個存儲單元,既然是同一個存儲單元,變數b和變數a本質上就是完全相同的,這就好比一個人除了本名之外,還有其他的名字,如筆名、昵稱、乳名等等,雖然本質一樣,但是可以在不同場合使用。
5.2關於Python的常量問題
在大多數語言中都有常量這個概念,但是Python卻沒有。其實仔細想想也好像沒有設置常量的必要,只要一個變數的值不發生變化,即不給變數重新賦值,它的值當然不會變化,它便是個常量。
5.3基本數據類型
5.3.1整數型和浮點數
整數型(integer),可以是正整數、負整數和0,可以是十進制、八進制、二進制等。
浮點數(float),由整數部分和小數部分組成,主要用於處理包括小數的數。浮點數也可以用科學計數法表示。
5.3.2 字元串類型
字元串類型是由一系列的字母或者其他符號組成的數據序列,通常用單引號、雙引號或三引號括起來。
用單引號和雙引號括起來的字元串只能放在同一行,用三引號括起來的字元串可以分布在連續多行上。如:
name='我的名字叫王小明'
old="今年6歲"
introce='''我想說: 我是中國娃
愛講普通話
要學習寫標準的漢字'''
print(name)
print(old)
print(introce)
運行結果為:我的名字叫王小明
今年6歲
我想說: 我是中國娃
愛講普通話
要學習寫標準的漢字
不管是哪一種引號形式,括起來的部分是一個整體,包括空格和換行符都屬於字元串的一部分。
為了保證特殊的輸出效果,Python中的字元串支持轉義字元,可使用反斜杠「」對一些特殊字元進行轉義。常用的轉義字元如下:
續行符
換行符
空
水平製表符
」 雙引號
』 單引號
一個反斜杠
f 換頁
其中,續行符(「」)用於當一個字元串在一行寫不下時用續行符進行連接,但通常更多的採用小括弧「()」即可。
如:
第一種方法採用續行符(「」):
>>> str="A thousand wishes, a thousand plans and
a thousand resolutions are better than one action!"
>>> print(str)
A thousand wishes, a thousand plans and a thousand resolutions are better than one action!
第二種方法採用小括弧():
>>> str=("A thousand wishes, a thousand plans and "
"a thousand resolutions are better than one action!")
>>> print(str)
A thousand wishes, a thousand plans and a thousand resolutions are better than one action!
下面舉例說明換行符(「 」)的用法:
>>> str=" 登鸛雀樓 白日依山盡, 黃河入海流。 欲窮千里目, 更上一層樓。 "
>>> print(str)
登鸛雀樓
白日依山盡,
黃河入海流。
欲窮千里目,
更上一層樓。
下面舉例說明使用轉義字元輸出雙引號(「)的方法:
>>> str="王之渙的詩《登鸛雀樓》中這樣寫道:" 白日依山盡,黃河入海流。欲窮千里目,更上一層樓。""
>>> print(str)
王之渙的詩《登鸛雀樓》中這樣寫道:" 白日依山盡,黃河入海流。欲窮千里目,更上一層樓。"
>>>
5.3.3布爾類型
布爾類型用來表示邏輯值,所謂邏輯判斷的結果,不外乎「真」或「假」兩種情況。在Python中「真」用True表示,「假」用False表示。如果布爾類型的變數參與算數運算,則True被當作1,False被當作0。
如:
>>> result=True
>>> print(result)
True
>>> print(result+1)
2
>>> result=False
>>> print(result)
False
>>> print(result+1)
1
5.3.4類型強制轉換
Python是一種弱數據類型語言,可以通過給變數重新賦值的方法改變數據類型。但有時為了強制改變數據類型,就要使用類型轉換函數來改變。
譬如,為了從鍵盤讀入成績的數據,可以用float()函數將input()語句讀入的字元串轉換為浮點數,再賦值給變數score。
>>> score=input("請輸入您的成績:")
請輸入您的成績:96.5 (從鍵盤輸入96.5)
為了計算成績比及格線高了多少分,使用下面的命令,發現出現了錯誤提示如下:
>>> score-60
Traceback (most recent call last):
File " ", line 1, in
score-60
TypeError: unsupported operand type(s) for -: 'str' and 'int'
這是屬於類型錯誤,原因是從鍵盤讀入的成績值(96.5)並非數值類型,不能參與算數運算。用type()函數可以進一步查詢變數score的數據類型。
>>> type(score)
使用float()函數進行強制轉換後,就可以解決上述問題:
>>> score=float(input("請輸入您的成績:"))
請輸入您的成績:96.5
>>> score=float(score)
>>> type(score)
>>> score-60
36.5
下表列舉了一些常用的類型轉換函數: