摘要:函數(shù)的參數(shù)作為引用時唯一支持的參數(shù)傳遞模式是共享傳參,它指函數(shù)的形參獲得實(shí)參中各個引用的副本,即形參是實(shí)參的別名。而在上面這個例子中,類的屬性實(shí)際上是形參所指向的對象所指對象,的別名。
《流暢的Python》筆記1. 變量、標(biāo)識、相等性和別名本篇是“面向?qū)ο髴T用方法”的第一篇,一共六篇。本篇主要是一些概念性的討論,內(nèi)容有:Python中的變量,對象標(biāo)識,值,別名,元組的某些特性,深淺復(fù)制,引用,函數(shù)參數(shù),垃圾回收,del命令,弱引用等,比較枯燥,但卻能解決程序中不易察覺的bug。
先用一個形象的比喻來說明Python中的變量:變量是標(biāo)注而不是盒子。也就是說,Python中的變量更像C++中的引用,最能說明這一點(diǎn)的就是多個變量指向同一個列表,但也有例外,在遇到某些內(nèi)置類型,比如字符串str時,變量則變成了“盒子”:
# 代碼1 >>> a = [1, 2] >>> b = a # 標(biāo)注,引用 >>> a.append(3) >>> b [1, 2, 3] >>> c = "c" >>> d = c # “盒子” >>> c = "cc" >>> d "c"
補(bǔ)充:說到了賦值方式,Python和C++一樣,也是等號右邊先執(zhí)行。
1.1 相等性( == )與標(biāo)識( is )用一個更學(xué)術(shù)的詞來替換“標(biāo)注”,那就是“別名”。在C++中,引用就是變量的別名,Python中也是,比如代碼1中的變量b就是變量a的別名,但如果是以下形式,變量b則不是a的別名:
# 代碼2 >>> a = [1, 2] >>> b = [1, 2] >>> a == b # a和b的值相等 True >>> a is b # a和b分別綁定了不同的對象,雖然對象的值相等 False
==檢測對象的值是否相等,is運(yùn)算符檢測對象的標(biāo)識(ID)是否相等,id()返回對象標(biāo)識的整數(shù)表示。一般判斷兩對象的標(biāo)識是否相等并不直接使用id(),更多的是使用is運(yùn)算符。
對象ID在不同的實(shí)現(xiàn)中有所不同:在CPython中,id()返回對象的內(nèi)存地址,但在其他Python解釋器中可能是別的值。但不管怎么,對象的ID一定唯一,且在生命周期中保持不變。
通常我們關(guān)心的是值,而不是標(biāo)識,所以==出現(xiàn)的頻率比is高。但在變量和單例值之間比較時,應(yīng)該使用is。目前,最常使用is檢測變量綁定的值是不是None,推薦的寫法是:
# 代碼3 x is None # 并非 x == None x is not None # 并非 x != None
is運(yùn)算符比==速度快,因?yàn)樗荒苤剌d,所以Python不用尋找并調(diào)用特殊方法,而是直接比較兩個對象的ID。a == b其實(shí)是語法糖,實(shí)際調(diào)用a.__eq__(b)。雖然繼承自object的__eq__方法也是比較對象的ID,結(jié)果和is一樣,但大多數(shù)內(nèi)置類型覆蓋了該方法,處理過程更復(fù)雜,這就是為什么is比==快。
1.2 元組的相對不可變性元組和大多數(shù)Python集合一樣,保存的是對象的引用。元組的不可變性其實(shí)是指tuple數(shù)據(jù)結(jié)構(gòu)的物理內(nèi)容(即保存的引用)不可變,與引用的對象無關(guān)。如果引用的對象可變,即便元組本身不可變,元素依然可變,不變的是元素的標(biāo)識:
# 代碼4 >>> t1 = (1, 2, [30, 40]) >>> t2 = (1, 2, [30, 40]) >>> t1 == t2 True >>> id(t1[-1]) 2019589413704 >>> t1[-1].append(99) >>> t1 (1, 2, [30, 40, 99]) >>> id(t1[-1]) # 內(nèi)容變了,標(biāo)識沒有變 2019589413704 >>> t1 == t2 False
這同時也說明,并不是每個元組都是可散列的!
2.深淺復(fù)制復(fù)制對象時,相等性和標(biāo)識之間的區(qū)別有更深入的影響。副本與源對象相等,但I(xiàn)D不同。而如果對象內(nèi)部還有其他對象,這就涉及到了深淺復(fù)制的問題:到底是復(fù)制內(nèi)部對象呢還是共享內(nèi)部對象?
2.1 默認(rèn)做淺復(fù)制對列表和其他可變序列來說,我們可以使用構(gòu)造方法或[:]來創(chuàng)建副本。然而,這兩種方法做的都是淺復(fù)制,它們只復(fù)制了最外層的容器,副本中的元素是源容器中元素的引用。如果所有元素都是不可變的,那這樣做沒問題,還能節(jié)省內(nèi)存;但如果其中有可變元素,這么做就可能出問題:
# 代碼5 l1 = [3, [11, 22], (7, 8)] l2 = list(l1) # <1> l1.append(100) l1[1].remove(22) print("l1:", l1, " l2:", l2) l2[1] += [33, 44] # <2> l2[2] += (10, 11) # <3> print("l1:", l1, " l2:", l2) # 結(jié)果 l1: [3, [11], (7, 8), 100] # 追加元素只影響了l1 l2: [3, [11], (7, 8)] # 但刪除l1[1]中的元素影響了兩個列表 l1: [3, [11, 33, 44], (7, 8), 100] # +=對可變對象是就地操作,影響了兩個列表 l2: [3, [11, 33, 44], (7, 8, 10, 11)] # +=對不可變對象會創(chuàng)建新對象,只影響了l2
以上代碼有3點(diǎn)需要解釋:
<1>:l1[1]和l2[1]指向同一列表,l1[2]和l2[2]指向同一元組。因?yàn)槭菧\復(fù)制,只是復(fù)制引用;
<2>:+=運(yùn)算對可變對象來說是就地運(yùn)算,不會創(chuàng)建新對象,所以對兩個列表都有影響;
<3>:+=運(yùn)算對元組這樣的不可變對象來說,等同于l2[2] = l2[2] + (10, 11),此操作隱式地創(chuàng)建了新對象,l2[2]重新綁定到了新對象,所以只有列表l2[2]發(fā)生了改變,而l1[2]沒有改變。
2.2 為任意對象做深復(fù)制和淺復(fù)制淺復(fù)制并非是一種錯誤,只是一種選擇。而有時我們需要的是深復(fù)制,即副本不共享內(nèi)部對象的引用。copy模塊提供的deepcopy和copy函數(shù)能為任意對象做深復(fù)制和淺復(fù)制。
# 代碼6 import copy l1 = [3, [11, 22]] l2 = copy.copy(l1) # 淺復(fù)制 l3 = copy.deepcopy(l1) # 深復(fù)制 l1[1].append(33) # 影響了l2,但沒有影響l3 print("l1:", l1, " l2:", l2, " l3:", l3) # 結(jié)果 l1: [3, [11, 22, 33]] l2: [3, [11, 22, 33]] l3: [3, [11, 22]]
在做深復(fù)制時,如果對象之間有循環(huán)引用,樸素的深復(fù)制算法(換句話說就是你自己寫的深復(fù)制算法)很可能會陷入無限循環(huán),然后報(bào)錯。deepcopy會記住已經(jīng)復(fù)制的對象,而不會進(jìn)入無限循環(huán):
# 代碼7 >>> a = [10, 20] >>> b = [a, 30] # 包含a的引用 >>> b [[10, 20], 30] >>> a.append(b) # 相互引用 >>> a [10, 20, [[...], 30]] >>> a[2][0] [10, 20, [[...], 30]] >>> a[2][0][2][0] [10, 20, [[...], 30]] >>> from copy import deepcopy >>> c = deepcopy(a) # 不會報(bào)錯,能正確處理相互引用的問題 >>> c [10, 20, [[...], 30]]
此外,深復(fù)制有時可能太深了。例如,對象可能會引用不該復(fù)制的外部資源或單例值,這時,深復(fù)制就不應(yīng)該復(fù)制這些值。如果要控制copy和deepcopy的行為,我們可以在對象中重寫特殊方法__copy__和__deepcopy__,具體內(nèi)容這里就不展開了,大家可以參考copy模塊的官方文檔。
3. 函數(shù)參數(shù)通過別名共享對象還能解釋Python中傳遞參數(shù)的方式,以及使用可變類型作為參數(shù)默認(rèn)值引起的問題。
3.1 函數(shù)的參數(shù)作為引用時Python唯一支持的參數(shù)傳遞模式是共享傳參(call by sharing),它指函數(shù)的形參獲得實(shí)參中各個引用的副本,即形參是實(shí)參的別名。這種方案的結(jié)果就是,函數(shù)可能會修改作為參數(shù)傳入的可變對象,但無法修改這些對象的標(biāo)識(不能把一個對象替換成另一個對象):
# 代碼8 def f(a, b): a += b return a x, y = 1, 2 print(f(x, y), x, y) a, b = [1, 2], [3, 4] print(f(a, b), a, b) t, u = (10, 20), (30, 40) print(f(t, u), t, u) # 結(jié)果 3 1 2 # x, y是不可變對象,沒有影響到x, y [1, 2, 3, 4] [1, 2, 3, 4] [3, 4] # x是可變對象,影響到了x (10, 20, 30, 40) (10, 20) (30, 40) # x沒有指向新的元組,但形參a指向了新的元組3.2 參數(shù)默認(rèn)值
不要使用可變類型作為參數(shù)的默認(rèn)值!其實(shí)這個問題在之前的文章“Python學(xué)習(xí)之路7-函數(shù)”的2.3小節(jié)中有所提及?,F(xiàn)在我們來看下面這個例子:
首先定義一個類:
# 代碼9 class Bus: def __init__(self, passengers=[]): # 默認(rèn)值是個可變對象 self.passengers = passengers def pick(self, name): self.passengers.append(name) def drop(self, name): self.passengers.remove(name)
下面是這個類的行為:
# 代碼10 >>> bus1 = Bus(["Alice", "Bill"]) # 直到第8行Bus的表現(xiàn)都是正常的 >>> bus1.passengers ["Alice", "Bill"] >>> bus1.pick("Charlie") >>> bus1.drop("Alice") >>> bus1.passengers ["Bill", "Charlie"] >>> bus2 = Bus() # 使用默認(rèn)值 >>> bus2.pick("Carrie") >>> bus2.passengers ["Carrie"] # 到目前為止也是正常的 >>> bus3 = Bus() # 也是用默認(rèn)值 >>> bus3.passengers ["Carrie"] # 不正常了! >>> bus3.pick("Dave") >>> bus2.passengers ["Carrie", "Dave"] # bus2的值也被改變了 >>> bus2.passengers is bus3.passengers # 這倆是同一對象的別名 True >>> bus1.passengers # bus1依然正常 ["Bill", "Charlie"]
上述行為的原因在于,參數(shù)的默認(rèn)值在導(dǎo)入模塊時計(jì)算,方法或函數(shù)的形參指向這個默認(rèn)值。而在上面這個例子中,類的屬性self.passengers實(shí)際上是形參passengers所指向的對象(所指對象,referent)的別名。而bus1行為正常是因?yàn)閺囊婚_始它的passengers就沒有指向默認(rèn)值。
這里有點(diǎn)像單例模式:參數(shù)的默認(rèn)值是唯一的,只要采用默認(rèn)值,不管創(chuàng)建多少個Bus的實(shí)例,它們的self.passengers都是同一個空列表[]對象的別名,不會為每一個實(shí)例多帶帶創(chuàng)建一個專屬的[]。
運(yùn)行上述代碼之后,可以查看Bus.__init__對象的__defaults__屬性,它存儲了參數(shù)的默認(rèn)值:
# 代碼11 >>> Bus.__init__.__defaults__ (["Carrie", "Dave"],) >>> Bus.__init__.__defaults__[0] is bus2.passengers # self.passengers就是一個別名! True
這也說明了為什么要用None作為接收可變值的參數(shù)的默認(rèn)值:
# 代碼12 class Bus: def __init__(self, passengers=None): # 默認(rèn)值是個可變對象 if passengers is None: # 并不推薦 if passengers == None 這種寫法 self.passengers = [] else: self.passengers = list(passengers) # 注意這里! -- snip --
代碼12中的第7行并不是直接把形參passengers賦值給self.passengers,而是形參的副本(這里是淺復(fù)制)。如果直接賦值,即self.passengers = passengers(self.passengers變成了用戶傳入的參數(shù)的別名),則用戶傳入的參數(shù)在運(yùn)行過程中可能會被修改,而這并不一定是用戶想要的,這便違反了"最少驚訝原則"(居然還真有這么個原則)
4. del和垃圾回收對象絕不會自行銷毀;然而,無法得到對象時,可能會被當(dāng)做垃圾回收?!狿ython語言參考手冊
del語句刪除變量(即"引用"),而不是對象。del命令可能導(dǎo)致對象被當(dāng)做垃圾回收,但這僅發(fā)生在當(dāng)刪除的變量保存的是對象的最后一個引用,或者無法得到對象時(如果兩個對象相互引用,如代碼7,當(dāng)它們的引用只存在二者之間時,垃圾回收程序會判定它們都無法獲取,進(jìn)而把它們都銷毀)。重新綁定也可能會導(dǎo)致對象的引用數(shù)量歸零,進(jìn)而對象被銷毀。
在CPython中,垃圾回收使用的主要算法是引用計(jì)數(shù)。實(shí)際上,每個對象都會統(tǒng)計(jì)有多少個引用指向自己。當(dāng)引用計(jì)數(shù)歸零時,對象立即被銷毀。但在其他Python解釋器中則不一定是引用計(jì)數(shù)算法。
補(bǔ)充:有個__del__特殊方法,它不是用來銷毀實(shí)例的,而是在實(shí)例被銷毀前用來執(zhí)行一些最后的操作,比如釋放外部資源等。我們不應(yīng)該在代碼中調(diào)用它,Python解釋器會在銷毀實(shí)例時先調(diào)用它(如果定義了),然后再釋放內(nèi)存。它相當(dāng)于C++中的析構(gòu)函數(shù)。
我們可以使用weakref.finalize來演示對象被銷毀時的情況:
# 代碼13 >>> import weakref >>> s1 = {1, 2, 3} >>> s2 = s1 >>> def bye(): # 它充當(dāng)一個回調(diào)函數(shù) ... print("Gone with the wind...") # 一定不要傳入待銷毀對象的綁定方法,否則會有一個指向?qū)ο蟮囊?>>> ender = weakref.finalize(s1, bye) # 在s1引用的對象上注冊bye回調(diào) >>> ender.alive True >>> del s1 >>> ender.alive True # 說明 del s1并沒有刪除對象 >>> s2 = "spam" Gone with the wind... # 引用計(jì)數(shù)為零,對象被刪除 >>> ender.alive False5. 弱引用
不知道大家看到上述代碼第15行時會不會產(chǎn)生如下疑惑:第8行代碼明明把s1引用傳給了finalize函數(shù)(為了監(jiān)控對象和調(diào)用回調(diào),必須要有引用),那么對象{1, 2, 3}則應(yīng)該至少有三個引用,可為什么最后它還是被銷毀了呢?這就牽扯到了弱引用這個概念。
5.1 weakref.ref弱引用不會妨礙所指對象被當(dāng)做垃圾回收,即弱引用不會增加對象的引用計(jì)數(shù)。(弱引用常被用于緩存,但具體用在緩存的哪些地方目前筆者還不清楚.....)
弱引用還是可調(diào)用對象,下面的代碼展示了如何使用weakref.ref實(shí)例獲取所指對象。
補(bǔ)充在代碼之前:Python控制臺會自動把結(jié)果不為None的表達(dá)式的結(jié)果綁定到變量_(下劃線)上。這也說明了一個問題:微觀管理內(nèi)存時,隱式賦值會為對象創(chuàng)建新引用,而這有可能會導(dǎo)致一些意外結(jié)果。
# 代碼14 >>> import weakref >>> a_set = {1, 2} # 對象{1, 2}的引用數(shù)+1 >>> wref = weakref.ref(a_set) # 并沒有增加所指對象的引用數(shù) >>> wref5.2 weakref集合>>> wref() # 弱引用是個可調(diào)用對象 {1, 2} # 發(fā)生了隱式賦值,變量 _ 指向了對象{1, 2},引用數(shù)+1 >>> a_set = {2, 3} # 引用數(shù) -1 >>> wref() # 所指對象依然存在,還沒有被銷毀 {1, 2} >>> wref() is None # 此時所指對象依然存在 False # 變量 _ 指向了對象False,對象{1, 2}引用數(shù)歸零,銷毀 >>> wref() is None # 驗(yàn)證所指對象已被銷毀 True
weakref.ref類其實(shí)是底層接口,供高級用途使用,一般程序最好使用werakref集合和finalize函數(shù),即最好使用WeakKeyDictionary、WeakValueDictionary、WeakSet和finalize(它們在內(nèi)部使用弱引用),不推薦自己動手創(chuàng)建并處理weakref.ref實(shí)例,除非你的工作就是專門和這些東西打交道的。
WeakValueDictionary類實(shí)現(xiàn)的是一種可變映射,里面的值("鍵值對"中的"值",而不是字典中的"值")是對象的弱引用。被引用的對象在程序中的其他地方被當(dāng)做垃圾回收后,對應(yīng)的鍵會自動從WeakValueDictionary中刪除。因此,它經(jīng)常用于緩存。(查看緩存中變量是否依然存在?給框架用?)
# 代碼15 >>> import weakref >>> class Cheese: ... def __init__(self, kind): ... self.kind = kind ... >>> stock = weakref.WeakValueDictionary() >>> catalog = [Cheese("Red Leicester"), Cheese("Parmesan")] >>> for cheese in catalog: ... stock[cheese.kind] = cheese ... >>> sorted(stock.keys()) ["Red Leicester", "Parmesan"] # 表現(xiàn)正常 >>> del catalog >>> sorted(stock.keys()) ["Parmesan"] # 這是怎么回事? >>> del cheese # 這是問題所在 >>> sorted(stock.keys()) []
臨時變量引用了對象,這可能會導(dǎo)致該變量的存在時間比預(yù)期長。通常,這對局部變量來說不是問題,因?yàn)樗鼈冊诤瘮?shù)返回時會被銷毀。但上述代碼中,for循環(huán)中的變量cheese是全局變量,除非顯示刪除,否則不會消失。
與WeakValueDictionary對應(yīng)的是WeakKeyDictionary,后者的鍵是弱引用,它的一些可能用途如下:
它的實(shí)例可以為應(yīng)用中其他部分擁有的對象附加數(shù)據(jù),這樣就無需為對象添加屬性。這對屬性訪問受限的對象尤其有用。
WeakSet類的用途則很簡單:"保存元素弱引用的集合。當(dāng)某元素沒有強(qiáng)引用時,集合會把它刪除。"如果一個類需要知道它的所有實(shí)例,一種好的方案是創(chuàng)建一個WeakSet類型的類屬性,保存實(shí)例的弱引用。
5.3 弱引用的局限weakref集合以及一般的弱引用,能處理的對象類型有限:
基本的list和dict實(shí)例不能作為弱引用的所指對象,但它們的子類則可以;
class MyList(list): """MyList的實(shí)例可作為弱引用的所指對象"""
set的實(shí)例可作為所指對象;
自定義類的實(shí)例可以;
int和tuple的實(shí)例不能作為弱引用的所指對象,它們的子類也不行。
但這些局限基本上是CPython的實(shí)現(xiàn)細(xì)節(jié),其他Python解釋器的情況可能不同。
6. CPython對不可變類型走的捷徑本節(jié)內(nèi)容是Python實(shí)現(xiàn)的細(xì)節(jié),可以跳過。
這些細(xì)節(jié)是CPython核心開發(fā)者走的捷徑和優(yōu)化措施,利用這些細(xì)節(jié)寫的代碼在其他Python解釋器中可能沒用,在CPython未來的版本中也可能沒用。下面是具體內(nèi)容:
對元組t來說,t[:]和tuple(t)不創(chuàng)建副本,而是返回同一個對象的引用;
str、bytes和frozenset實(shí)例也是如此,并且frozenset的copy方法返回的也不是副本(注意,frozenset的實(shí)例fs不能用fs[:],因?yàn)?b>fs不是序列);
str的實(shí)例還有共享字符串字面量的行為:
>>> s1 = "ABC" >>> s2 = "ABC" >>> s1 is s2 True
這叫做"駐留"(interning),這是一種優(yōu)化措施。CPython還會在小的整數(shù)上使用這種優(yōu)化,防止重復(fù)創(chuàng)建常用數(shù)字,如0,-1。但CPython不會駐留所有字符串和數(shù)字,駐留的條件是實(shí)現(xiàn)細(xì)節(jié),而且沒有文檔說明。所以千萬不要依賴這個特性!(比較字符串或數(shù)字請用==,而不是is?。?/p>
7. 總結(jié)每個Python對象都有標(biāo)識、類型和值,只有對象的值可能變化。
變量保存的是引用,這對Python編程有很多實(shí)際的影響:
簡單的賦值不會創(chuàng)建副本;
對+=或*=等運(yùn)算符來說,如果左邊的變量綁定了不可變對象,則會創(chuàng)建新對象,然后重新綁定;如果是可變對象,則就地修改;
對現(xiàn)有的變量賦予新值不會修改之前綁定的對象。這叫重新綁定:現(xiàn)有變量綁定了其它對象。如果變量是之前那個對象的最后一個引用,該對象會被回收;
函數(shù)的參數(shù)以別名的形式傳遞,這意味著,函數(shù)可能會修改通過參數(shù)傳入的可變對象。這一行為無法避免,除非在函數(shù)內(nèi)部創(chuàng)建副本,或者使用不可變對象;
不要使用可變類型作為函數(shù)的默認(rèn)值!
==用于比較值,is用于比較引用。
某些情況下,可能需要保存對象的引用,但不留存對象本身,比如記錄某個類的所有實(shí)例,這可以用弱引用解決。
迎大家關(guān)注我的微信公眾號"代碼港" & 個人網(wǎng)站 www.vpointer.net ~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/41836.html
摘要:一對象引用基礎(chǔ)知識變量是標(biāo)注而不是容器。也就是說元組中不可變的是元素的標(biāo)識,但元組的值會隨著引用的可變對象變化而變化。在中每個對象的引用都會有統(tǒng)計(jì)。弱引用不會妨礙對象被當(dāng)做垃圾回收。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之面向?qū)ο笃闹攸c(diǎn)知識及個人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、明確變量保存的是引用這一本質(zhì);2、熟悉對象引用的基礎(chǔ)知識;...
摘要:每個變量都有標(biāo)識類型和值對象一旦創(chuàng)建它的標(biāo)識絕不會變標(biāo)識可以簡單的理解為對象在內(nèi)存中的地址別名跟是別名指向如果增加新的內(nèi)容也會增加相等性為運(yùn)算符比較連個對象的值對象中保存的數(shù)據(jù)標(biāo)識為因?yàn)樗麄兌贾赶蜻@個列表比較對象的標(biāo)識元組相對不可變性元組保 a = [1,2,3,4] b = a 每個變量都有標(biāo)識,類型和值.對象一旦創(chuàng)建,它的標(biāo)識絕不會變;標(biāo)識可以簡單的理解為對象在內(nèi)存中的地址. ...
摘要:里,有兩種方法獲得一定范圍內(nèi)的數(shù)字返回一個列表,還有返回一個迭代器。在引用計(jì)數(shù)的基礎(chǔ)上,還可以通過標(biāo)記清除解決容器對象可能產(chǎn)生的循環(huán)引用的問題。列舉常見的內(nèi)置函數(shù)的作用,過濾函數(shù),循環(huán)函數(shù)累積函數(shù)一行代碼實(shí)現(xiàn)乘法表。 showImg(https://segmentfault.com/img/remote/1460000019294205); 1、為什么學(xué)習(xí)Python? 人生苦短?人間...
摘要:運(yùn)算符比較兩個對象的標(biāo)識函數(shù)返回對象標(biāo)識的整數(shù)表示。實(shí)際上,每個對象都會統(tǒng)計(jì)有多少引用指向自己。對象被銷毀了,調(diào)用了回調(diào),的值變成了。當(dāng)對象的引用數(shù)量歸零后,垃圾回收程序會把對象銷毀。引用的目標(biāo)對象稱為所指對象。 對象不是個盒子 showImg(https://segmentfault.com/img/bV95mW?w=1784&h=988); class Gizmo: def...
摘要:對象引用和可變性變量不是盒子,而是便利貼變量的賦值方式比如是將一個變量分配給一個對象比如整數(shù)。運(yùn)算符比較兩個對象的標(biāo)識函數(shù)返回對象標(biāo)識的整數(shù)表示。每個對象都會統(tǒng)計(jì)有多少引用指向自己。對象被銷毀執(zhí)行回調(diào)函數(shù)輸出 對象引用和可變性 變量不是盒子,而是‘便利貼’ >>> a = [1,2,3] >>> b = a >>> a.append(5) >>> a [1, 2, 3, 5] >>> ...
閱讀 596·2019-08-30 15:55
閱讀 1015·2019-08-29 15:35
閱讀 1269·2019-08-29 13:48
閱讀 2000·2019-08-26 13:29
閱讀 3014·2019-08-23 18:26
閱讀 1312·2019-08-23 18:20
閱讀 2893·2019-08-23 16:43
閱讀 2761·2019-08-23 15:58