本文整理類中對象與屬性(變量)相關知識。
類對象與實例對象
建立測試類:
class Test:
var_of_class = 'Class Var'
def __init__(self):
self.var_of_instance = 'Instance Var'
類對象
建立類進行編譯後則形成了類對象,類對象僅支持兩個操作:
- 實例化:使用
instance_name = class_name()
的方式實例化,實例化操作創建該類的實例。 - 屬性引用:使用
class_name.attr_name
的方式引用類屬性。
實例對象
類對象實例化得到實例對象,實例對象僅支持一個操作:
- 屬性引用;與類對象屬性引用的方式相同,使用
instance_name.attr_name
的方式
# 類對象
print(Test)
# 實例對象
class_instance = Test()
>>>
<class '__main__.Test'>
<__main__.Test object at 0x00000127715B4128>
類變量與實例變量
建立測試類:
class Test:
var_of_class = 'Class Var'
def __init__(self):
self.var_of_instance = 'Instance Var'
類變量
可由類對象引用
由所有實例共享
# 類對象引用類變量
print(f'類對象引用類變量 :{Test.var_of_class}')
class_instance_1 = Test()
class_instance_2 = Test()
# 實例對象引用類變量
print(f'實例對象1引用類變量 :{class_instance_1.var_of_class}')
print(f'實例對象2引用類變量 :{class_instance_2.var_of_class}')
# 修改類變量實例對象共享修改
Test.var_of_class = 'Changed Class Var'
print(f'實例對象1引用類變量 :{class_instance_1.var_of_class}')
print(f'實例對象2引用類變量 :{class_instance_2.var_of_class}')
>>>
類對象引用類變量 :Class Var
實例對象1引用類變量 :Class Var
實例對象2引用類變量 :Class Var
實例對象1引用類變量 :Changed Class Var
實例對象2引用類變量 :Changed Class Var
實例變量
由實例對象引用
僅在當前實例保存
# 實例變量
class_instance_1 = Test()
class_instance_2 = Test()
print(f'實例對象1實例變量 :{class_instance_1.var_of_instance}')
print(f'實例對象2實例變量 :{class_instance_2.var_of_instance}')
class_instance_1.var_of_instance = 'changed instance var'
print(f'修改實例對象1後實例對象1實例變量 :{class_instance_1.var_of_instance}')
print(f'修改實例對象1後實例對象2實例變量 :{class_instance_2.var_of_instance}')
>>>
實例對象1實例變量 :Instance Var
實例對象2實例變量 :Instance Var
修改實例對象1後實例對象1實例變量 :changed instance var
修改實例對象1後實例對象2實例變量 :Instance Var
類對象不能引用實例變量:
# 類對象不能引用實例變量
print(Test.var_of_instance)
>>> 報錯!
type object 'Test' has no attribute 'var_of_instance'
屬性綁定
建立測試類:
class Test():
var_of_class = 'Class Var'
def __init__(self):
self.var_of_instance = 'Instance Var'
在定義、使用類、實例對象屬性過程中,其實涉及兩個過程:
- 類屬性綁定
- 實例屬性綁定
使用
綁定
一詞事實上更加確切,可以理解爲屬性並不是屬於類或實例的,Python中一切皆對象,每個屬性也都是一個個現貨鮮活的對象,之所以這些對象被稱之爲、用作於屬性,是因爲我們將這部分對象綁在了類對象可使用的屬性名稱上;換一種說法,對象就是對象,而世上本沒有屬性,當對象被綁定在類/實例上,對象也就成了類/實例的屬性。
因此綁定屬性,首先需要有一個對象纔行。
類屬性綁定
Python作爲動態語言,類對象和實例對象都可以在運行時綁定任意屬性,因此類屬性綁定有兩種時機:
- 編譯類時(寫在類中的類屬性)
- 運行時
# 定義時綁定類屬性
print(f'定義時綁定類屬性:{Test.var_of_class}')
# 運行時綁定類屬性
Test.var_of_class_defined_during_running = 'a long var of class'
print(f'運行時綁定類屬性:{Test.var_of_class_defined_during_running}')
>>>
定義時綁定類屬性:Changed Class Var
運行時綁定類屬性:a long var of class
實例屬性綁定
實例屬性綁定也發生在兩個時機:
- 實例生成時
- 運行時
class_instance = Test()
# 實例生成時綁定的實例屬性
print(f'實例生成時綁定的實例屬性:{class_instance.var_of_instance}')
# 實例運行時綁定的實例屬性
class_instance.var_of_instance = 'defined during running'
print(f'實例運行時綁定的實例屬性{class_instance.var_of_instance}')
>>>
實例生成時綁定的實例屬性:Instance Var
實例運行時綁定的實例屬性: defined during running
屬性引用
上文中對屬性的使用事實上都是在引用類對象或實例對象中的屬性。
需要特別說明的是實例對象的屬性引用衝突的問題,當類中存在同名的實例屬性與類屬性時:
- 由於類對象無法訪問實例屬性,因此對類對象的屬性引用沒有影響
- 實例屬性有權訪問二者,實現上會優先引用實例級的屬性,即同名的類屬性會被覆蓋
class_instance = Test()
class_instance.var_of_class = 'instance var with a same name of a class var'
print(f'類對象引用衝突屬性:{Test.var_of_class}')
print(f'實例對象引用衝突屬性:{class_instance.var_of_class}')
>>>
類對象引用衝突屬性:Changed Class Var
實例對象引用衝突屬性:instance var with a same name of a class var
獲取源碼
文中測試環境與所有源碼可在Github下載。