class Gizmo: def __init__(self): print('Gizmo id: %d' % id(self)) x = Gizmo() print(x) y = Gizmo() * 10 print(y) print(dir())
❶ 輸出的 Gizmo id: ... 是建立 Gizmo 實例的反作用。
❷ 在乘法運算中使用 Gizmo 實例會拋出異常。
❸ 這裏代表,在嘗試求積以前其實會建立一個新的 Gizmo 實例。
❹ 可是,確定不會建立變量 y,由於在對賦值語句的右邊進行求值時拋出了異常。
longe = {'name': 'longe', 'born': 1993} liang = longe print(liang is longe) print(id(liang), id(longe)) longe['balance'] = 950 print(liang) ## 冒充的longe信息 other = {'name': 'longe', 'born': 1993, 'balance': 950} print(other) print(other is longe)
❶ liang 是 longe 的別名。
❷ is 運算符和 id 函數確認了這一點。
❸ 向 liang 中添加一個元素至關於向 longe 中添加一個元素。html
在那段代碼中,liang 和 longe 是別名,即兩個變量綁定同一個對象。
而 other 不是 longe 的別名,由於兩者綁定的是不一樣的對象。pythonother 和longe 綁定的對象具備相同的值(== 比較的就是值),可是它們的標識不一樣。
== 運算符比較兩個對象的值(對象中保存的數據),而 is 比較對象的標識。算法
元組的不可變性實際上是指 tuple 數據結構的物理內容(即保存的引用)不可變,與引用的對象無關編程
>>> t1 = (1, 2, [30, 40]) ➊ >>> t2 = (1, 2, [30, 40]) ➋ >>> t1 == t2 ➌ True >>> id(t1[-1]) ➍ 4302515784 >>> t1[-1].append(99) ➎ >>> t1 (1, 2, [30, 40, 99]) >>> id(t1[-1]) ➏ 4302515784 >>> t1 == t2 ➐ False
基礎理解!!!仍是能夠的
>>> l1 = [3, [55, 44], (7, 8, 9)] >>> l2 = list(l1) ➊ >>> l2 [3, [55, 44], (7, 8, 9)] >>> l2 == l1 ➋ True >>> l2 is l1 ➌ False
然而,構造方法或 [:] 作的是淺複製(即複製了最外層容器,副本中的元素是源容器中
元素的引用)。若是全部元素都是不可變的,那麼這樣沒有問題,還能節省內存。緩存
import copy class Bus: def __init__(self, passengers=None): if passengers is None: self.passengers = [] else: self.passengers = list(passengers) def pick(self, name): self.passengers.append(name) def drop(self, name): self.passengers.remove(name) bus1 = Bus(['Alice', 'Bill', 'Claire', 'David']) bus2 = copy.copy(bus1) bus3 = copy.deepcopy(bus1) print(id(bus1), id(bus2), id(bus3)) bus1.drop('Bill') print(bus2.passengers) print(id(bus1.passengers), id(bus2.passengers), id(bus3.passengers)) print(bus3.passengers)
❸ 審查 passengers 屬性後發現,bus1 和 bus2 共享同一個列表對象,由於 bus2 是
bus1 的淺複製副本。
❹ bus3 是 bus1 的深複製副本,所以它的 passengers 屬性指代另外一個列表。數據結構
注意,通常來講,深複製不是件簡單的事。若是對象有循環引用,那麼這個樸素的算法會進入無限循環
>>> a = [10, 20] >>> b = [a, 30] >>> a.append(b) >>> a [10, 20, [[...], 30]] >>> from copy import deepcopy >>> c = deepcopy(a) >>> c [10, 20, [[...], 30]]
深複製有時可能太深了。例如,對象可能會引用不應複製的外部資源或單例值。咱們能夠實現特殊方法 __copy__() 和 __deepcopy__(),控制 copy 和 deepcopy 的行爲
共享傳參指函數的各個形式參數得到實參中各個引用的副本。也就是說,函數內部的形參
是實參的別名。app
def f(a, b): a += b return a a = [1, 2] b = [3, 4] print(f(a, b)) print(a, b)
這裏變量全都是引用,不管局部變量仍是全局.
因此上面案例中,a會變化函數
class HauntedBus: """備受幽靈乘客折磨的校車""" def __init__(self, passengers=[]): #別使用這種可變類型 做爲默認參數 self.passengers = passengers
class TwilightBus: """正常的校車""" def __init__(self, passengers=None): if passengers is None: self.passengers = [] else: self.passengers = list(passengers) ##這裏會產生副本(能夠理解爲深拷貝) def pick(self, name): self.passengers.append(name) def drop(self, name): self.passengers.remove(name) bus1 = TwilightBus(("sfs", 'sdf')) bus2 = TwilightBus(["sdfsdfsfd111"]) bus1.pick("ppxia") bus1.drop("sfs") print(bus1.passengers) bus2.drop("sdfsdfsfd111") print(bus2.passengers)
儘可能別用可變類型作默認參數值, 實在要用,必須使其產生副本
>>> import weakref >>> s1 = {1, 2, 3} >>> s2 = s1 ➊ >>> def bye(): ➋ ... print('Gone with the wind...') ... >>> ender = weakref.finalize(s1, bye) ➌ >>> ender.alive ➍ True >>> del s1 >>> ender.alive ➎ True >>> s2 = 'spam' ➏ Gone with the wind... >>> ender.alive False
❺ 如前所述,del 不刪除對象,而是刪除對象的引用。
❻ 從新綁定最後一個引用 s2,讓 {1, 2, 3} 沒法獲取。對象被銷燬了,調用了 bye 回
調,ender.alive 的值變成了 False。測試
>>> import weakref >>> a_set = {0, 1} >>> wref = weakref.ref(a_set) ➊ >>> wref <weakref at 0x100637598; to 'set' at 0x100636748> >>> wref() ➋ {0, 1} >>> a_set = {2, 3, 4} ➌ >>> wref() ➍ {0, 1} >>> wref() is None ➎ False >>> wref() is None ➏ True
❷ 調用 wref() 返回的是被引用的對象,{0, 1}。由於這是控制檯會話,因此 {0, 1}
會綁定給 _ 變量。
❸ a_set 再也不指代 {0, 1} 集合,所以集合的引用數量減小了。可是 _ 變量仍然指代
它。
❹ 調用 wref() 依舊返回 {0, 1}。
❺ 計算這個表達式時,{0, 1} 存在,所以 wref() 不是 None。可是,隨後 _ 綁定到結
果值 False。如今 {0, 1} 沒有強引用了。
❻ 由於 {0, 1} 對象不存在了,因此 wref() 返回 None。spa