Python類變量和實例變量

我們知道,無論是在類中定義的屬性還是方法,在類的外部,都無法直接調用它們,因此,我們完全可以把類看做是一個獨立的作用域(稱爲類命名空間),則類屬性其實就是定義在類命名空間內的變量(類方法其實就是定義的類命名空間中的函數)。

根據定義屬性的位置不同,類屬性又可細分爲類屬性(後續用類變量表示)和實例屬性(後續用實例變量表示)。

類變量(類屬性)

類變量指的是定義在類中,但在各個類方法外的變量。類變量的特點是:所有類的實例化對象都可以共享類變量的值,即類變量可以在所有實例化對象中作爲公用資源。

注意,類變量推薦直接用類名訪問,但也可以使用對象名訪問。

例如,下面代碼定義了一個 Address 類,併爲該類定義了多個類屬性:

class Address :
    detail = '廣州'
    post_code = '510660'
    def info (self):
        # 嘗試直接訪問類變量
        #print(detail) # 報錯
        # 通過類來訪問類變量
        print(Address.detail) # 輸出 廣州
        print(Address.post_code) # 輸出 510660
#創建 2 個類對象
addr1 = Address()
addr1.info()
addr2 = Address()
addr2.info()
# 修改Address類的類變量
Address.detail = '佛山'
Address.post_code = '460110'
addr1.info()
addr2.info()

該程序中,第二、三行代碼爲 Address 定義了兩個類變量。當程序中第一次調用 Address 對象的 info() 方法輸出兩個類變量時,將會輸出這兩個類變量的初始值。接下來程序通過 Address 類修改了兩個類變量的值,因此當程序第二次通過 info() 方法輸出兩個類變量時,將會輸出這兩個類變量修改之後的值。

運行上面代碼,將會看到如下輸出結果:

廣州
510660
廣州
510660
佛山
460110
佛山
460110

通過輸出結果可以看到,addr1 和 addr2 共享類變量,換句話說,改變類變量的值會作用於該類所有的實例化對象。

當然,Python 也支持使用對象來訪問該對象所屬類的類屬性(此方式不推薦使用)。例如如下程序:

class Record:
    # 定義兩個類變量
    item = '鼠標'
    date = '2016-06-16'
    def info (self):
        print('info方法中: ', self.item)
        print('info方法中: ', self.date)
rc = Record()
print(rc.item) # '鼠標'
print(rc.date) # '2016-06-16'
rc.info()

上面程序的 Record 中定義了兩個類變量,接下來程序完全可以使用 Record 對象來訪問這兩個類變量。

因此可以看到,在 Record 類的 info() 方法中,程序使用 self 訪問 Record 類的類變量,此時 self 代表 info() 方法的調用者,也就是 Record 對象,因此這是合法的;在主程序代碼區,程序創建了 Record 對象,並通過對象調用 Record 對象的 item、date 類變量,這也是合法的。

在 Python 中,除了可以通過類名訪問類屬性之外,還可以動態地爲類和對象添加類變量。例如,在上面代碼的基礎,添加以下代碼:

Address.depict ="佛山很美"
print(addr1.depict)
print(addr2.depict)

運行結果爲:

佛山很美
佛山很美

實例變量(實例屬性)

實例變量指的是定義在類的方法中的屬性,它的特點是:只作用於調用方法的對象。

注意,實例變量只能通過對象名訪問,無法通過類名直接訪問。

Python 允許通過對象訪問類變量,但無法通過對象修改類變量的值。因爲,通過對象修改類變量的值,不是在給“類變量賦值”,而是定義新的實例變量。

例如如下程序:

class Inventory:
    # 定義兩個類變量
    item = '鼠標'
    quantity = 2000
    # 定義實例方法
    def change(self, item, quantity):
        # 下面賦值語句不是對類變量賦值,而是定義新的實例變量
        self.item = item
        self.quantity = quantity
# 創建Inventory對象
iv = Inventory()
iv.change('顯示器', 500)
# 訪問iv的item和quantity實例變量
print(iv.item) # 顯示器
print(iv.quantity) # 500
# 訪問Inventory的item和quantity類變量
print(Inventory.item) # 鼠標
print(Inventory.quantity) # 2000

上面程序中,第 8、9 行代碼通過實例對 item、quantity 變量賦值,看上去很像是對類變量賦值,但並不是,它們的作用是:重新定義了兩個實例變量。

類中,實例變量和類變量可以同名,但是在這種情況下,使用類對象將無法調用類變量,因爲它會首選實例變量,因此這也是不推薦“類變量使用對象名調用”的原因。

上面程序在調用 Inventory 對象的 change() 方法之後,訪問 Inventory 對象的 item、quantity 變量,由於該對象本身己有這兩個實例變量,因此程序將會輸出該對象的實例變量的值;接下來程序通過 Inventory 訪問它的 item、quantity 兩個類變量,此時纔是真的訪問類變量。

運行上面程序,將看到如下輸出結果:

顯示器
500
鼠標
2000

即便程序通過類修改了兩個類變量的值,程序中 Inventory 的實例變量的值也不會受到任何影響。例如如下代碼:

Inventory.item = '類變量item'
Inventory.quantity = '類變量quantity'
# 訪問iv的item和quantity實例變量
print(iv.item)
print(iv.quantity)

運行上面代碼,可以看到如下輸出結果:

顯示器
500

上面程序開始就修改了 Inventory 類中兩個類變量的值,但這種修改對 Inventory 對象的實例變量沒有任何影響。

同樣,如果程序對一個對象的實例變量進行了修改,這種修改也不會影響類變量的值,更不會影響其他對象中實例變量的值。例如如下代碼:

iv2 = Inventory()
iv2.change('鍵盤',300)
iv.item = 'iv實例變量item'
iv.quantity = 'iv實例變量quantity'
print(Inventory.item)
print(Inventory.quantity)

print(iv.item)
print(iv.quantity)

運行上面代碼,將會看到如下輸出結果:

類變量item
類變量quantity
iv實例變量item
iv實例變量quantity
鍵盤
300

從輸出結果很容易看出,修改一個對象的實例變量,既不會影響類變量的值,也不會影響其它對象的實例變量。

和動態爲類添加類變量不同,Python 只支持爲特定的對象添加實例變量。例如,在之前代碼的基礎上,爲 iv 對象添加 color 實例變量,實現代碼爲:

iv.color="red"
print(iv.color)
#因爲 color 實例變量僅 iv 對象有,iv2 對象並沒有,因此下面這行代碼會報錯
#print(iv2.color)

 

發佈了73 篇原創文章 · 獲贊 10 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章