類(Class)
關(guān)于類(Class)叉讥,是一個(gè)很抽象的概念测蹲。本篇幅簡單介紹關(guān)于類的一些基礎(chǔ)內(nèi)容像屋。更多深入的內(nèi)容,可詳閱官方文檔:
https://docs.python.org/3/tutorial/index.html
在 Python 中电禀,所有的數(shù)據(jù)類型都可以視為對象幢码,也可以自定義對象。自定義對象數(shù)據(jù)類型就是類(Class)的概念尖飞。
Python 的類提供了面向?qū)ο缶幊痰乃袠?biāo)準(zhǔn)特性:類繼承機(jī)制允許多個(gè)基類症副,派生類可以覆蓋基類的任何方法,一個(gè)方法可以調(diào)用基類中相同名稱的方法政基。
類定義語法
最簡單的類定義的語法如下:
class ClassName:
<statement-1>
.
.
.
<statement-N>
類定義贞铣,和函數(shù)定義類似,必須定義執(zhí)行后才能生效沮明。
類對象
類對象支持兩種操作:屬性引用和實(shí)例化辕坝。
這里的屬性引用使用的是 Python 中所有屬性引用的標(biāo)準(zhǔn)語法:obj.name
。有效的屬性名稱是類對象被創(chuàng)建存在于類命名空間的所有名稱荐健。假設(shè)酱畅,類定義如下:
class MyClass:
"""A simple example class"""
i = 123
def func(self):
return "hello world"
在這里 MyClass.i
和 Myclass.func
屬于有效屬性,分別返回一個(gè)整數(shù)和一個(gè)函數(shù)對象江场。類屬性可以被賦值纺酸,所以也可以通過賦值改變 MyClass.i
的值。在這里 __doc__
也是一個(gè)有效的屬性址否,它返回的是一個(gè)所屬類的文檔字符串:"A simple example class"
餐蔬。
類的實(shí)例化使用函數(shù)表示法。例如,沿用上面的類:
x = MyClass()
創(chuàng)建類的實(shí)例樊诺,并將此對象賦值給變量 x仗考。在這個(gè)實(shí)例化操作的過程中,創(chuàng)建的是一個(gè)空對象啄骇。但許多類喜歡創(chuàng)建帶特定初始狀態(tài)的自定義實(shí)例。因此瘟斜,一個(gè)類能夠定義一個(gè)特殊的方法:__init__()
缸夹,例如:
def __init__(self):
self.data = []
如果一個(gè)類定義了 __init__()
方法,創(chuàng)建新的實(shí)例的時(shí)候螺句,會自動調(diào)用該方法虽惭。
當(dāng)然,這個(gè)方法還能夠有額外的參數(shù)蛇尚。在這種情況下芽唇,提供給類實(shí)例化的參數(shù)都會傳遞給 __init__()
,例如:
>>> class Student:
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
>>> s = Student('demon', 21)
>>> s.name, s.age
('demon', 21)
實(shí)例對象
從屬性引用來理解實(shí)例對象取劫。兩種有效的屬性名稱包括:數(shù)據(jù)屬性和方法匆笤。
數(shù)據(jù)屬性不需要聲明:它會像局部變量一樣,在首次賦值的時(shí)候產(chǎn)生谱邪。
另一種實(shí)例屬性引用稱為方法炮捧。方法是從屬于對象的函數(shù)。(方法并非類實(shí)例所特有的惦银,其他對象也有方法咆课。本篇幅若無特別說明,方法一詞專指類實(shí)例對象的方法)
實(shí)例對象的有效方法名稱依賴于所屬的類扯俱。根據(jù)定義书蚪,一個(gè)類所有為對象的屬性都定義了與實(shí)例的相應(yīng)方法。
在上面自定義的 MyClass
類中迅栅,x.func
是有效的方法引用殊校,因?yàn)?MyClass.func
是一個(gè)函數(shù),而 x.i
并不是方法读存,因?yàn)?MyClass.i
并不是一個(gè)函數(shù)箩艺。但 x.func
并不是就等同于 MyClass.func
,因?yàn)?x.func
是一個(gè)方法對象宪萄,不是函數(shù)對象艺谆。
方法對象
在上面 MyClass
的例子中,執(zhí)行下面的語句:
x.func()
這個(gè)時(shí)候回返回 hello world
拜英。但是静汤,當(dāng)不想馬上就調(diào)用方法時(shí),因?yàn)?`x.func
` 是一個(gè)方法對象,可以將其賦值給一個(gè)變量虫给,等待后面調(diào)用藤抡。
xf = x.func
print(xf())
當(dāng)執(zhí)行 print
語句時(shí),同樣會返回 hello world
抹估。
將前面的例子重新放到這里:
class MyClass:
"""A simple example class"""
i = 123
def func(self):
return "hello world"
x = MyClass()
在前面執(zhí)行 x.func()
的時(shí)候缠黍,這里并沒有帶參數(shù),但是在 func 的函數(shù)定義時(shí)药蜻,指定了一個(gè) self
參數(shù)瓷式。
這就是方法特殊的地方,實(shí)例對象會作為函數(shù)的第一個(gè)參數(shù)被傳入语泽。其實(shí)調(diào)用 x.func
等同于 MyClass.func(x)
贸典。
類和實(shí)例變量
一般來說,實(shí)例變量用于每個(gè)實(shí)例的唯一數(shù)據(jù)踱卵,類變量用于類的所有實(shí)例共享的屬性和方法廊驼,如下實(shí)例:
class Dog:
# 類變量,用于所有實(shí)例共享
kind = 'canine'
def __init__(self, name):
# 實(shí)例變量惋砂,每個(gè)實(shí)例專有
self.name = name
>>> d = Dog('Emy')
>>> e = Dog('Buddy')
>>> d.kind
'canine'
>>> e.kind
'canine'
>>> d.name
'Emy'
>>> e.name
'Buddy'
由上面的例子可以看出妒挎, kind
類變量是所有實(shí)例共有的,而實(shí)例變量 name
則是每個(gè)實(shí)例獨(dú)有的西饵。
需要注意的是饥漫,共享的數(shù)據(jù)若是涉及到可變對象,往往得到的結(jié)果并不是期望的結(jié)果罗标。例如:
class Dog:
tricks = []
def __init__(self, name):
self.name = name
def add_tricks(self, trick):
self.tricks.append(trick)
>>> d = Dog('Emy')
>>> e = Dog('Buddy')
>>> d.add_tricks('roll over')
>>> e.add_tricks('play dead')
>>> d.tricks
['roll over', 'play dead']
>>> e.tricks
['roll over', 'play dead']
在這里可以看出庸队,列表不應(yīng)該被用作類變量。正確的類設(shè)計(jì)應(yīng)該使用實(shí)例變量:
class Dog:
def __init__(self, name):
self.name = name
self.tricks = []
def add_tricks(self, trick):
self.tricks.append(trick)
>>> d = Dog('Emy')
>>> e = Dog('Buddy')
>>> d.add_tricks('roll over')
>>> e.add_tricks('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
注意事項(xiàng): 數(shù)據(jù)屬性會覆蓋具有相同名稱的方法屬性闯割。若是程序當(dāng)中的代碼量夠大彻消,這種情況很有可能會發(fā)生。所以可以做某些約定來最小化這種可能產(chǎn)生沖突的情況宙拉。例如在屬性名稱前加一個(gè)下劃線宾尚,或者方法屬性用動詞來命名,名詞來命名數(shù)據(jù)屬性谢澈。
以上就是關(guān)于類(Class)的一部分基礎(chǔ)內(nèi)容煌贴,后續(xù)會另開篇幅繼續(xù)介紹類的其他相關(guān)內(nèi)容。
歡迎關(guān)注微信公眾號《書所集錄》