在個人一個業務邏輯代碼中,我不幸須要編寫如下類(這裏咱們用抽象的A, B, C表示)python
class A: value = 0 def __init__(self, b): self.b = b def set_1(self): self.value = 1 class B: def __init__(self): pass def reset(self): self.a = A(self)
這是兩個沒有什麼問題的對象,不過在建立B的實例時,會讓本身的屬性a指向一個A的實例,而a中的屬性b又指向該B實例
因此咱們能夠像下面這樣訪問:函數
b = B() a = b.a assert b.a.b is b assert b.a.b.a is a
這樣可以使得b擁有a的控制權,也同時使得a擁有b的控制權。編碼
可是當我試圖用一個類C來代理實例b時,卻犯了一個錯誤代理
class C: b = B() a = b.a def __init__(self): pass def read_a(self): return self.b.a.value c = C() assert c.read_a() == 0 c.a.set_1() assert c.read_a() == 1 c.b.reset() assert c.read_a() == 0 assert c.a == 0 # AssertionError
爲何這裏我會腦子抽斷言 c.a == 0呢?
由於我主觀地認爲這裏實例b執行了reset函數,因而從新實例化了屬性b.a=A(self)
那麼a在實例過程當中,會讓a.value = 0
因此 c.b.a.value == 0
而咱們的c.a = b.a
因此c.a.value == c.b.a.value == 0
幾乎完美的推理!!!code
可是我忽略了,這裏的c.a is not c.b.a !!!
緣由以下:
假設一開始實例化A, B 爲 a1, b1
c.a -> a1
c.b -> b1
那麼當b1.reset() 的時候,a是從新實例化的一個A對象,用JAVA的話來講,就是從新new 了一個A
b1.a -> a2
故c.b.a == c.b1.a == a2
而c.a == a1
a1.value在a1.set_1()以後,賦值爲 1
a2.value在b1.reset()以後,賦值爲 0
因此斷言錯誤對象
記錄這個錯誤警告本身在從此的編碼過程當中不要一味主觀地用數學觀點,而要弄清楚具體對象。數學