第7.12節 可共享的Python類變量
一、 引言
在上節已經引入介紹了類變量和實例變量,類體中定義的變量為類變量,默認屬於類本身,實例變量是實例方法中定義的self對象的變量,對於每個實例都是獨有數據,而類變量是該類所有實例共享的屬性和方法。
二、 類變量的定義方式
類變量的定義其實就是對變量賦值,有如下方式可以進行類變量的定義:
1. 在類體代碼中,直接用變量名賦值。類體代碼是在類定義時執行;
2. 在實例方法中(含構造方法和普通方法),直接用“類名.變量名”方式賦值;
3. 在類方法中,直接用“類名.變量名”或“cls.變量名”方式賦值,關於cls請參考下面“類方法”章節的解釋;
4. 在類外調用方代碼中直接用“類名.變量名”方式賦值。
注意:類變量無論是哪種方法定義后,會立即對該類所有實例對象產生影響,所有實例無論是類變量定義前就產生的實例還是類變量定義后的實例都可以訪問該變量。
三、 類變量的訪問方式
類變量的訪問方式與類變量的定義方式有2點不同,一是因為類體代碼僅在類定義時執行,因此不能在類定義后再通過類體代碼訪問,二是類變量可以在類外調用方通過實例方式訪問。具體支持的訪問方式如下:
1. 在實例方法中(含構造方法和普通方法),直接用“類名.變量名”方式訪問;
2. 在類方法中,直接用“類名.變量名”方式訪問;
3. 在類外調用方代碼中直接用“類名.變量名”方式訪問;
4. 在類外調用方代碼中直接用“實例名.變量名”方式訪問,注意這種方式不能用來直接賦值,只能讀取,如果是賦值就變成了實例變量的定義。
從以上說明中,可以得知:
1. 類變量是可以在類定義的實例方法和類方法、以及類外調用時動態增加,並且一旦增加,對所有已經定義及后續需要新定義的實例變量都可見;
2. 程序通過對象訪問類變量,其本質還是通過類名在訪問類變量,但如果類變量和實例變量重名時,必須通過類名才能訪問類變量。這是因為Python總是先到實例對象中查找屬性,再到類屬性中查找屬性,有點類似局部變量和全局變量的關系;
3. Python 允許通過對象訪問類變量,但如果程序通過對象嘗試對類變量賦值,此時性質就變了,Python 是動態語言,賦值語句往往意味着定義新的實例變量。因此,如果程序通過對象對類變量賦值,其實不是對“類變量賦值”,而是定義新的實例變量。
如果把類當成類命名空間,那么類變量其實就是定義在類命名空間內的變量, Python 可以使用類來讀取、修改類變量。對於類變量而言,它們就是屬於在類命名空間內定義的變量,因此程序不能直接訪問這些變量,主要使用類名的方式來訪問類變量,同時Python 完全允許使用實例對象來訪問該對象所屬類的類變量,但Python主要推薦使用類名訪問類變量。因此老猿強烈建議大家使用類名訪問類變量,使用實例方式訪問很容易出錯,大家可以結合下面的舉例好好理解一下。
四、 舉例
1、 定義一個類VarTest和實例,在類體代碼中對類變量classvar賦值
class VarTest():
classvar='classvar在類體代碼賦值'
定義個實例:var=VarTest()
2、 查看相關變量的值
查看var.classvar和VarTest.classvar的值,都顯示為:'classvar在類體代碼賦值'
執行:var.classvar is VarTest.classvar,返回True
3、 執行賦值語句
var.classvar='classvar在類外通過實例賦值'
4、 再次查看相關變量的值
此時查看var.classvar和VarTest.classvar的值,二者已經不同,一個是'classvar在類外通過實例賦值',一個是'classvar在類體代碼賦值'
執行:var.classvar is VarTest.classvar,返回False
相關代碼執行截圖:
5、 如果上面第3個步驟不是通過直接給變量賦值,而是先引用再賦值會怎么樣?看下面代碼的執行情況:
注本次新定義一個實例,可以看到最開始的var1.classvar和VarTest.classvar是同一個變量,執行var1.classvar+=的操作語句,這個語句的效果等同於“var1.classvar=var1.classvar+' 在類體外通過實例訪問類變量'”
可以看到,執行后還是新定義了一個實例變量。
本節介紹了類變量的定義和使用方法,並舉例進行了說明,雖然類變量的定義和訪問可以通過實例方式進行,但老猿強烈推薦大家按類名方式進行定義和訪問。
老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用於逐步介紹老猿學習Python后總結的學習經驗,這些經驗有助於沒有接觸過Python的程序員可以很容易地進入Python的世界。
歡迎大家批評指正,謝謝大家關注!