Class Variables 演練與變數記憶體關係範例

class Counter:
    total = 0

    def __init__(self):
        Counter.total += 1

a = Counter()
b = Counter()
c = Counter()
print(Counter.total)



測試重點詳解:

類別變數 total 的定義與初始化:
  • total = 0 定義在 class Counter: 區塊內,而不是在任何方法(如 __init__)中,這使得 total 成為一個類別變數。
  • 特性: 所有透過 Counter 類別建立的物件(實例,如 a、b、c)都會共享這同一個 total 變數。
__init__ 構造函數中的操作:
  • def __init__(self): 是在物件被建立時自動呼叫的方法。
  • Counter.total += 1 確保了每當一個 Counter 類別的物件被建立時,共享的類別變數 total 的值就會增加 1。

程式碼執行過程:

a = Counter():建立第一個物件,Counter.total 變為 0 + 1 = 1。
b = Counter():建立第二個物件,Counter.total 變為 1 + 1 = 2。
c = Counter():建立第三個物件,Counter.total 變為 2 + 1 = 3。

最終輸出:

print(Counter.total) 最終會輸出 3。




但是,更進階一點,如果程式寫成下面的方式

class Counter:
    total = 0
    def __init__(self):
        print(f"Counter.total={Counter.total}, id={id(Counter.total)}")
        Counter.total += 1
        self.total += 2
        print(f"self.total={self.total}, id={id(self.total)}")
        
        
a = Counter()
b = Counter()
c = Counter()
print(Counter.total)
print(a.total)
print(b.total)
print(c.total)


這時使用 self.total,就是以當時被建立的實力底下的 total來做計算。所以, a, b, c 三個個別的實例,會因為當時共用的 Counter.total 所計算的結果再進行一次 "+2" 的動作。
所以輸出結果會變成:

Counter.total=0, id=10914880         <-- id(0) 
self.total=3, id=10914976               <-- id(3) (a.total) 
Counter.total=1, id=10914912         <-- id(1) (新的整數物件) 
self.total=4, id=10915008               <-- id(4) (b.total) 
Counter.total=2, id=10914944        <-- id(2) (新的整數物件) 
self.total=5, id=10915040               <-- id(5) (c.total)








所以

直接調用 Counter.total 和 Counter() 呼叫後,調用其中的 a.total 意義是不同的。
而在自己類別當中使用的意義也是不一樣的。
所以要特別記清楚!!



留言

這個網誌中的熱門文章

Python 變數是參考還是值?用實驗帶你看懂