十四、類變數和實列變數(python)

不會做飯的廚師 不是好程式設計師發表於2020-12-12

無論是類屬性還是類方法,都無法像普通變數或者函式那樣,在類的外部直接使用它們。我們可以將類看做一個獨立的空間,則類屬性其實就是在類體中定義的變數,類方法是在類體中定義的函式。

前面章節提到過,在類體中,根據變數定義的位置不同,以及定義的方式不同,類屬性又可細分為以下 3 種型別:

  1. 類體中、所有函式之外:此範圍定義的變數,稱為類屬性或類變數;
  2. 類體中,所有函式內部:以“self.變數名”的方式定義的變數,稱為例項屬性或例項變數;
  3. 類體中,所有函式內部:以“變數名=變數值”的方式定義的變數,稱為區域性變數。
不僅如此,類方法也可細分為例項方法、靜態方法和類方法,後續章節會做詳細介紹。

那麼,類變數、例項變數以及區域性變數之間有哪些不同呢?接下來就圍繞此問題做詳細地講解。

類變數(類屬性)

類變數指的是在類中,但在各個類方法外定義的變數。舉個例子:

class CLanguage :
    # 下面定義了2個類變數
    name = "C語言中文網"
    add = "http://c.biancheng.net"
    # 下面定義了一個say例項方法
    def say(self, content):
        print(content)

上面程式中,name 和 add 就屬於類變數。

類變數的特點是,所有類的例項化物件都同時共享類變數,也就是說,類變數在所有例項化物件中是作為公用資源存在的。類方法的呼叫方式有 2 種,既可以使用類名直接呼叫,也可以使用類的例項化物件呼叫。

比如,在 CLanguage 類的外部,新增如下程式碼:

#使用類名直接呼叫
print(CLanguage.name)
print(CLanguage.add)
#修改類變數的值
CLanguage.name = "Python教程"
CLanguage.add = "http://c.biancheng.net/python"
print(CLanguage.name)
print(CLanguage.add)

程式執行結果為:

C語言中文網
http://c.biancheng.net
Python教程
http://c.biancheng.net/python

可以看到,通過類名不僅可以呼叫類變數,也可以修改它的值。

當然,也可以使用類物件來呼叫所屬類中的類變數(此方式不推薦使用,原因後續會講)。例如,在 CLanguage 類的外部,新增如下程式碼:

clang = CLanguage()
print(clang.name)
print(clang.add)

執行程式,結果為:

C語言中文網
http://c.biancheng.net

注意,因為類變數為所有例項化物件共有,通過類名修改類變數的值,會影響所有的例項化物件。例如,在 CLanguage 類體外部,新增如下程式碼:

print("修改前,各類物件中類變數的值:")
clang1 = CLanguage()
print(clang1.name)
print(clang1.add)
clang2 = CLanguage()
print(clang2.name)
print(clang2.add)
print("修改後,各類物件中類變數的值:")
CLanguage.name = "Python教程"
CLanguage.add = "http://c.biancheng.net/python"
print(clang1.name)
print(clang1.add)
print(clang2.name)
print(clang2.add)

程式執行結果為:

修改前,各類物件中類變數的值:
C語言中文網
http://c.biancheng.net
C語言中文網
http://c.biancheng.net
修改後,各類物件中類變數的值:
Python教程
http://c.biancheng.net/python
Python教程
http://c.biancheng.net/python

顯然,通過類名修改類變數,會作用到所有的例項化物件(例如這裡的 clang1 和 clang2)。

注意,通過類物件是無法修改類變數的。通過類物件對類變數賦值,其本質將不再是修改類變數的值,而是在給該物件定義新的例項變數(在講例項變數時會進行詳細介紹)。

值得一提的是,除了可以通過類名訪問類變數之外,還可以動態地為類和物件新增類變數。例如,在 CLanguage 類的基礎上,新增以下程式碼:

clang = CLanguage()
CLanguage.catalog = 13
print(clang.catalog)

執行結果為:

13

例項變數(例項屬性)

例項變數指的是在任意類方法內部,以“self.變數名”的方式定義的變數,其特點是隻作用於呼叫方法的物件。另外,例項變數只能通過物件名訪問,無法通過類名訪問。

舉個例子:

class CLanguage :
    def __init__(self):
        self.name = "C語言中文網"
        self.add = "http://c.biancheng.net"
    # 下面定義了一個say例項方法
    def say(self):
        self.catalog = 13

此 CLanguage 類中,name、add 以及 catalog 都是例項變數。其中,由於 init() 函式在建立類物件時會自動呼叫,而 say() 方法需要類物件手動呼叫。因此,CLanguage 類的類物件都會包含 name 和 add 例項變數,而只有呼叫了 say() 方法的類物件,才包含 catalog 例項變數。

例如,在上面程式碼的基礎上,新增如下語句:

clang = CLanguage()
print(clang.name)
print(clang.add)
#由於 clang 物件未呼叫 say() 方法,因此其沒有 catalog 變數,下面這行程式碼會報錯
#print(clang.catalog)
clang2 = CLanguage()
print(clang2.name)
print(clang2.add)
#只有呼叫 say(),才會擁有 catalog 例項變數
clang2.say()
print(clang2.catalog)

執行結果為:

C語言中文網
http://c.biancheng.net
C語言中文網
http://c.biancheng.net
13

前面講過,通過類物件可以訪問類變數,但無法修改類變數的值。這是因為,通過類物件修改類變數的值,不是在給“類變數賦值”,而是定義新的例項變數。例如,在 CLanguage 類體外,新增如下程式:

clang = CLanguage()
#clang訪問類變數
print(clang.name)
print(clang.add)
clang.name = "Python教程"
clang.add = "http://c.biancheng.net/python"
#clang例項變數的值
print(clang.name)
print(clang.add)
#類變數的值
print(CLanguage.name)
print(CLanguage.add)

程式執行結果為:

C語言中文網
http://c.biancheng.net
Python教程
http://c.biancheng.net/python
C語言中文網
http://c.biancheng.net

顯然,通過類物件是無法修改類變數的值的,本質其實是給 clang 物件新新增 name 和 add 這 2 個例項變數。

類中,例項變數和類變數可以同名,但這種情況下使用類物件將無法呼叫類變數,它會首選例項變數,這也是不推薦“類變數使用物件名呼叫”的原因。

另外,和類變數不同,通過某個物件修改例項變數的值,不會影響類的其它例項化物件,更不會影響同名的類變數。例如:

class CLanguage :
    name = "xxx"  #類變數
    add = "http://"  #類變數
    def __init__(self):
        self.name = "C語言中文網"   #例項變數
        self.add = "http://c.biancheng.net"   #例項變數
    # 下面定義了一個say例項方法
    def say(self):
        self.catalog = 13  #例項變數
clang = CLanguage()
#修改 clang 物件的例項變數
clang.name = "python教程"
clang.add = "http://c.biancheng.net/python"
print(clang.name)
print(clang.add)
clang2 = CLanguage()
print(clang2.name)
print(clang2.add)
#輸出類變數的值
print(CLanguage.name)
print(CLanguage.add)

程式執行結果為:

python教程
http://c.biancheng.net/python
C語言中文網
http://c.biancheng.net
xxx
http://

不僅如此,Python 只支援為特定的物件新增例項變數。例如,在之前程式碼的基礎上,為 clang 物件新增 money 例項變數,實現程式碼為:

clang.money = 30
print(clang.money)

區域性變數

除了例項變數,類方法中還可以定義區域性變數。和前者不同,區域性變數直接以“變數名=值”的方式進行定義,例如:

class CLanguage :
    # 下面定義了一個say例項方法
    def count(self,money):
        sale = 0.8*money
        print("優惠後的價格為:",sale)
clang = CLanguage()
clang.count(100)

通常情況下,定義區域性變數是為了所在類方法功能的實現。需要注意的一點是,區域性變數只能用於所在函式中,函式執行完成後,區域性變數也會被銷燬。

相關文章