(點選上方公眾號,可快速關註一起學Python)
作者:浪子燕青 連結:
http://www.langzi.fun/深入類與物件-中.html
類屬性和實體屬性查詢順序
屬性:在內部定義的方法或者變數
使用程式碼:
class magic:
a = 'langzi'
def __init__(self,x):
self.x = x
# 這裡傳入的x已經屬於這個物件
def run(self):
return self.x
m = magic('xx')
m.a = 'LANGZILANGZI'
print(m.a)
# 查詢實體的屬性
print(magic.a)
# 查詢類的屬性
print(m.x)
# 查詢實體的屬性
傳回結果:
'LANGZILANGZI'
'langzi'
'xx'
查詢順序是由下而上的查詢順序,init是初始化實體的屬性,要記住這裡使用magic.x是會報錯的,因為init是初始化實體,這個實體成為m,並不在屬於magic。
可能這樣舉例子不清晰,重新再看看程式碼
class magic:
name = '浪子'
def __init__(self,name):
self.name = name
m = magic('langzi')
print(m.name)
print(magic.name)
傳回結果:
langzi
浪子
這樣是不是就比較清晰了,類中的name=’浪子’是屬於magic類當中的,實體m.name是屬於實體m當中的,是在類中init初始化的屬性。
他們的查詢順序是這樣:
- 找m.name的時候,由下而上,會先找到m。
- 找到m的初始話物件,從init開始查詢,就會找到初始化傳入的name
- 如果init中沒有name的話,就會往上走,查詢類中是不是存在name
就好像這樣的程式碼:
class magic:
# def __init__(self,name):
# self.name = name
name = '浪子'
m = magic()
print(m.name)
print(magic.name)
傳回結果:
浪子
浪子
三大方法
python類的呼叫有三大方法,分別是類方法,靜態方法,實體方法。這三個方法在曾經的文章有說過。
這裡就不多做程式碼重寫,去原連結檢視學習即可。
資料封裝與私有屬性
私有屬性,也叫私有方法,是以雙下劃線開頭的命名變數。
無法透過實體方法和子類來呼叫的,只能透過類中寫的方法來呼叫。
比如:
class magic:
__user = '浪子'
a = magic
print(magic.__user)
print(a.__user)
加了雙下劃線的user就是私有屬性,是沒法透過下麵兩種方式進行呼叫的,唯一可以呼叫這個私有屬性的方法就是使用類方法。
class magic:
__user = '浪子'
@classmethod
def run(cls):
print(cls.__user)
magic.run()
只有這樣才能呼叫類的私有屬性,這也就是對資料做了一個很好的封裝。
但是這樣的封裝並不是完全安全的,比如你看下麵的程式碼:
class magic:
__user = '浪子'
m = magic
print(m._magic__user)
這樣能直接呼叫user,說白了這是一個小技巧python把私有變數偷偷隱藏起來變成了這樣子。
python的自省機制
自省:透過一定的機制,查詢到物件的內部結構
使用__dict__方法查詢類的屬性:
class magic:
'我是註釋'
user = '浪子'
def run(age):
print(age)
for x,y in magic.__dict__.items():
print(x,':',y)
傳回結果:
__module__ : __main__
__doc__ : 我是註釋
user : 浪子
run : 0x0000018AB312CC80
>
__dict__ : ‘__dict__’ of ‘magic’ objects>
__weakref__ : ‘__weakref__’ of ‘magic’ objects>
透過dict來獲取類的內部結果,記住透過magic.__dict__[‘user’]=’小桃紅’也可以動態操作屬性。
不僅僅是dict,透過dir可以更加強大的列出該類的所有屬性。
super函式
super函式,呼叫父類。在類的繼承中,如果重定義某個方法,該方法會改寫父類的同名方法,但有時,我們希望能同時實現父類的功能,這時,我們就需要呼叫父類的方法了,可透過使用 super 來實現。
class A:
def __init__(self,name):
self.name = name
def run(self):
print(self.name+'6666666')
class B(A):
def __init__(self,name):
self.name = name
def run(self):
print(self.name+'7777777')
super().run()
#這裡是呼叫父類的run()方法
# 還可以這樣super().__init__(name=name)這樣的格式
c = B('浪子')
c.run()
傳回物件:
浪子7777777
浪子6666666
事實上,super 和父類沒有實質性的關聯,super(cls, inst) 獲得的是 cls 在 inst 的 MRO 串列中的下一個類。MRO則是python中類繼承關係選擇的一種,有點像是廣度優先原則,可以print m.__mro__檢視。