Python变量的理解与内存管理
Python變量與內存管理
–與C語言中的變量做對比,更好的理解Python的變量。
變量
變量在C語言中
全局變量:其存放在內存的靜態變量區中。
局部變量:代碼塊中存放在內存的代碼區當中,當被調用后存放在內存棧區。
Python中的變量與變量存儲–引用與對象
Python作為OOP(面向對象)編程,一直信奉著一個信條,就是萬物皆對象。
所謂對象,它可以看成經過一系列的抽象以后,將具有共性的一類物體進行實例化(具象化)的個體,就如同我們每個人就是人類里面的一個對象。
輸出的是:
class ‘function’
class ‘int’
class ‘main.A’
class ‘list’
class ‘dict’
class ‘tuple’
class ‘str’
很明顯,Python中不管是基礎數據類型,類,函數,所有的一切都是作為一個類的對象存儲在內存,也可以單純的看做一個值。
而Python的變量就是作為一個引用,讀取對象所存儲的信息,與C面向過程所不同,Python變量即對象的引用,通俗來說就是指向值的名稱。
所以Python的變量只是不過對于一塊指定內存的引用,也即對對象的引用,或者稱為指向值的名稱,相對于全局變量,局部變量的賦值只是引用另一塊內存。C語言中一個變量代表一塊特定的內存,而Python不像C語言,可以看成數據已經存放在內存之中了,被Python的變量對內存進行引用。即使變量不存在了,內存里值也不會受到任何影響。
if __name__ == "__main__":a = 1b = 2print(id(a))print(id(b))a = bprint(id(a))print(id(1))print(id(2))sys.exit(0)輸出的是:
10919424
10919456
10919456
10919424
10919456
從輸出結果來看,很明顯同一塊內存數據其實是可以被多個變量引用,且常量和變量的內存地址是相對應的。
輸出結果:
10919424
10919424
10919456
10919424
從輸出結果可以看出,若是當全局變量和局部變量的數值一致時,其對應的內存地址是一致的,當全局變量被賦予其他值時,其內存地址發生改變,而局部變量未有變化。
總結:Python變量的定義和賦值是同時進行的,Python的全局變量和局部變量的定義聲明時,是基于內存已有數據的基礎上,為變量分配地址進行引用,變量即對象的引用,而不是分別分配一塊內存進行賦值,所以變量不進行賦值的話就會出現未定義的錯誤,,這時就會出現一個問題,這將會造成一個問題就是對象和數據將會越來越多,會消耗很大的內存空間,這時將會啟動Python的垃圾回收機制,當某一段內存塊的引用計數為0時進行回收,這個是后話了。
變量的作用域—看不見的字典
C語言中每一對大括號作為一個代碼塊,if,for,while,switch語句是可以加上大括號的作為一個塊級作用域,for,while()語句在括號中定義的變量是包含在大括號里面的,就是包含在大括號的作用域里,而每一個代碼塊就是一個局部的作用域,所有代碼塊內部變量優先級大于代碼塊外的同名變量。
Python的作用域,就如同是Python的基礎類型中的一部字典,在這部字典里記錄著值(對象)與指向值的名稱(變量),不同的作用域組成了不同的字典,而Python中能改變變量作用域的關鍵字只有class,def,lamba,所以在Python的關鍵語句(if,for,while…)中是不進行作用域的劃分的,所以在(if,for,while…)語句對變量進行賦值,其變量的作用域可以被外部所引用。
并且Python不存在塊級作用域,在嵌套作用域中會生成作用域鏈,由內到外,引用時優先選取內部同名變量。
在類與實例的作用域中
輸出的是:
A name id = 140654891768216
set global name = 140654890720536
set.name = xxx
A id = 20336920
a id = 140654890787168
A.name = 140654891768216
a.name id = 140654890720704
A.what id = 140654890720536
a.what id = 140654890720536
A.set id = 140654690844744
a.set id = 140654891845576
所以,作用域是對于變量而言的而不是內存而言,類與實例的作用域也是嵌套的
參考LEGB法則:
Local(本地作用域)–>Enclosing(閉包作用域)–>Global(全局作用域)–>Built-in(內建作用域)
函數內部–>嵌套函數內部–>模塊內部–>Python內建
LEGB法則: 當在函數中使用未確定的變量名時,Python會按照優先級依次搜索4個作用域,以此來確定該變量名的意義。首先搜索局部作用域(L),之后是上一層嵌套結構中def或lambda函數的閉包作用域(E),之后是全局作用域(G),最后是內建作用域(B)。按這個查找原則,在第一處找到的地方停止。如果沒有找到,則會發出錯誤。
變量作用域在定義時已經設定好,與調用的位置無關。
輸出的是:
???
所以變量的作用域與是否調用無關,在變量定義時所處作用域已經設定完成。
變量的生命周期—只要被需要便存在
C語言的局部變量是在函數調用完畢后進行自動銷毀,釋放棧區。
而基于Python存儲方式的特殊性,所以變量在函數調用完畢之后,并未立刻銷毀,對于Python的變量和變量所引用的對象,是使用類似堆的方式管理內存,由Python內部機制統一分配回收內存,當內存的某一對象或者變量的引用計數為0時則由Python的內存管理機制收回內存,或者對對象手動del掉對象以釋放內存,不過del掉的對象不影響對象中依然被外部變量有引用的值。
輸出結果是:
39697096
1409448784
39697096
1409448784
1409448784
當函數被調用完,只要類實例還被引用,那么類實例依然存在類似c++的new,當del對象時,不影響對象還在被外部變量引用的值。
當我們若是del掉classA后,再輸入print(id(classA)),會出現如下錯誤:
總結
以上是生活随笔為你收集整理的Python变量的理解与内存管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 虚拟服务器启动顺序,虚拟机开机启动项设置
- 下一篇: python实现链表(一)