原文作者:Jeff Knupp
原文鏈接:這里
<font color=red>class
</font>是Python的基礎(chǔ)構(gòu)建快。它是很多流行的程序和庫,以及Python標(biāo)準(zhǔn)庫的基礎(chǔ)依托。理解類是什么,什么時候使用,以及它們?nèi)绾斡杏弥陵P(guān)重要,這也是本文的目的。在這個過程中,我們會探討“面向?qū)ο缶幊獭钡暮x,以及它與Python類之間的聯(lián)系。
一切都是對象...
<font color=red>class
</font>關(guān)鍵字究竟是什么?跟它基于函數(shù)的<font color=red>def
</font>表兄弟類似,它用于定義事物。<font color=red>def
</font>用來定義函數(shù),<font color=red>class
</font>用來定義類。什么是類?就是一個數(shù)據(jù)和函數(shù)(在類中定義時,通常叫做“方法”)的邏輯分組。
“邏輯分組”是什么意思?一個類可以包含我們希望的任何數(shù)據(jù)和函數(shù)(方法)。我們嘗試創(chuàng)建事物之間有邏輯聯(lián)系的類,而不是把隨機(jī)的事物放在“類”名下面。很多時候,類都是基于真實世界的物體(比如<font color=red>Customer
</font>和<font color=red>Product
</font>)。其它時候,類基于系統(tǒng)中的概念,比如<font color=red>HTTPRequest
</font>和<font color=red>Owner
</font>。
不管怎么樣,類是一種建模技術(shù),一種思考程序的方式。當(dāng)你用這種方式思考和實現(xiàn)你的系統(tǒng)時,被稱為使用面向?qū)ο缶幊?/strong>。“類”和“對象”經(jīng)常互換使用,但實際上它們并不相同。理解它們是什么和它們是如何工作的關(guān)鍵是理解它們之間的區(qū)別。
..所以一切都有一個類?
類可以看做是創(chuàng)建對象的藍(lán)圖。當(dāng)我使用<font color=red>class
</font>關(guān)鍵字定義一個Customer
類時,我并沒有真正創(chuàng)建一個顧客。相反,我創(chuàng)建的是構(gòu)建顧客
對象的說明手冊。讓我們看以下示例代碼:
class Customer(object):
"""A customer of ABC Bank with a checking account. Customers have the
following properties:
Attributes:
name: A string representing the customer's name.
balance: A float tracking the current balance of the customer's account.
"""
def __init__(self, name, balance=0.0):
"""Return a Customer object whose name is *name* and starting
balance is *balance*."""
self.name = name
self.balance = balance
def withdraw(self, amount):
"""Return the balance remaining after withdrawing *amount*
dollars."""
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
self.balance -= amount
return self.balance
def deposit(self, amount):
"""Return the balance remaining after depositing *amount*
dollars."""
self.balance += amount
return self.balance
<font color=red>class Customer(object)
</font>并沒有創(chuàng)建一個新的顧客。我們只是定義了一個<font color=red>Customer
</font>,并不意味著創(chuàng)建
了一個顧客;我們僅僅勾勒出創(chuàng)建<font color=red>Customer
</font>對象的藍(lán)圖
。用正確的參數(shù)數(shù)量(去掉<font color=red>self
</font>,我們馬上會討論)調(diào)用類的<font color=red>__init__
</font>方法可以創(chuàng)建一個顧客。
因此,要使用通過<font color=red>class Customer
</font>(用于創(chuàng)建<font color=red>Customer
</font>對象)定義的“藍(lán)圖”,可以把類名看做一個函數(shù)來調(diào)用:<font color=red>jeff = Customer('Jeff Knupp', 1000.0)
</font>。這行代碼表示:使用<font color=red>Customer
</font>藍(lán)圖創(chuàng)建一個新對象,并把它指向<font color=red>jeff
</font>。
被稱為實例的<font color=red>jeff
</font>對象是<font color=red>Customer
</font>類的實現(xiàn)版本。我們調(diào)用<font color=red>Customer()
</font>之前,不存在<font color=red>Customer
</font>對象。當(dāng)然,我們可以創(chuàng)建任意多個<font color=red>Customer
</font>對象。但是不管我們創(chuàng)建多少<font color=red>Customer
</font>實例,仍然只有一個<font color=red>Customer
</font>類。
<font color=red>self
</font>?
對應(yīng)所有<font color=red>Customer
</font>方法來說,<font color=red>self
</font>參數(shù)是什么?當(dāng)然,它是實例。換一種方式,像<font color=red>withdraw
</font>這樣的方法,定義了從某些抽象顧客的賬戶中取錢的指令。調(diào)用<font color=red>jeff.withdraw(1000.0)
</font>把這些指令用在<font color=red>jeff
</font>實例上。
所以,當(dāng)我們說:<font color=red>def withdraw(self, amount):
</font>,我們的意思是:這是你如何從一個顧客對象(我們稱為<font color=red>self
</font>)和一個美元數(shù)字(我們稱為<font color=red>amount
</font>)取錢。<font color=red>self
</font>是<font color=red>Customer
</font>的實例,在它上面調(diào)用<font color=red>withdraw
</font>。這也不是我做類比。<font color=red>jeff.withdraw(1000.0)
</font>只是<font color=red>Customer.withdraw(jeff, 1000.0)
</font>的簡寫,也是完全有限的代碼。
<font color=red>__init__
</font>
<font color=red>self
</font>可能對其它方法也有意義,但是<font color=red>__init__
</font>呢?當(dāng)我們調(diào)用<font color=red>__init__
</font>時,我們在創(chuàng)建一個對象的過程中,為什么已經(jīng)有了<font color=red>self
</font>?盡管不完全適合,Python還是允許我們擴(kuò)展<font color=red>self
</font>模式到對象的構(gòu)造。想象<font color=red>jeff = Customer('Jeff Knupp', 1000.0)
</font>等價于<font color=red>jeff = Customer(jeff, 'Jeff Knupp', 1000.0)
</font>;傳入的<font color=red>jeff
</font>也是同樣的結(jié)果。
這就是為什么調(diào)用<font color=red>__init__
</font>時,我們通過<font color=red>self.name = name
</font>來初始化對象。記住,因為<font color=red>self
</font>是實例,所以它等價于<font color=red>jeff.name = name
</font>,它等價于<font color=red>jeff.name = 'Jeff Knupp'
</font>。同樣的,<font color=red>self.balance = balance
</font>等價于<font color=red>jeff.balance = 1000.0
</font>。這兩行代碼之后,我們認(rèn)為<font color=red>Customer
</font>對象已經(jīng)“初始化”,可以被使用。
完成<font color=red>__init__
</font>后,調(diào)用者可以假設(shè)對象已經(jīng)可以使用。也就是,調(diào)用<font color=red>jeff = Customer('Jeff Knupp', 1000.0)
</font>后,我們可以在<font color=red>jeff
</font>上調(diào)用<font color=red>deposit
</font>和<font color=red>withdraw
</font>;<font color=red>jeff
</font>是一個完全初始化的對象。
我們定義了另外一個稍微不同的<font color=red>Customer
</font>類:
class Customer(object):
"""A customer of ABC Bank with a checking account. Customers have the
following properties:
Attributes:
name: A string representing the customer's name.
balance: A float tracking the current balance of the customer's account.
"""
def __init__(self, name):
"""Return a Customer object whose name is *name*."""
self.name = name
def set_balance(self, balance=0.0):
"""Set the customer's starting balance."""
self.balance = balance
def withdraw(self, amount):
"""Return the balance remaining after withdrawing *amount*
dollars."""
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
self.balance -= amount
return self.balance
def deposit(self, amount):
"""Return the balance remaining after depositing *amount*
dollars."""
self.balance += amount
return self.balance
它看起來是一個合理的替代者;在使用實例之前,只需要簡單的調(diào)用<font color=red>set_balance
</font>。但是,沒有一種方式可以告訴調(diào)用者這么做。即使我們在文檔中說明了,也不能強(qiáng)制調(diào)用者在調(diào)用<font color=red>jeff.withdraw(100.0)
</font>之前調(diào)用<font color=red>jeff.set_balance(1000.0)
</font>。<font color=red>jeff
</font>實例在調(diào)用<font color=red>jeff.set_balance
</font>之前沒有<font color=red>balance
</font>屬性,這意味著對象沒有“完全”初始化。
簡單來說,不要在<font color=red>__init__
</font>方法之外引入新的屬性,否則你會給調(diào)用一個沒有完全初始化的對象。當(dāng)然也有例外,但這是一個需要記住的原則。這是對象一致性這個大概念的一部分:不應(yīng)該有任何一系列的方法調(diào)用可能導(dǎo)致對象進(jìn)入沒有意義的狀態(tài)。
不變性(比如“賬戶余額總是非負(fù)數(shù)”)應(yīng)該在方法進(jìn)入和退出時都保留。對象不可能通過調(diào)用它的方法進(jìn)入無效狀態(tài)。不用說,一個對象也應(yīng)該從一個有效的狀態(tài)開始,這就是為什么在<font color=red>__init__
</font>方法中初始化所有內(nèi)容是很重要的。
實例屬性和方法
定義在類中的函數(shù)稱為“方法”。方法可以訪問包含在對象實例中的所有數(shù)據(jù);它們可以訪問和修改之前在<font color=red>self
</font>上設(shè)置的任何內(nèi)容。因為它們使用<font color=red>self
</font>,所以需要使用類的一個實例。基于這個原因,它們通常被稱為“實例方法”。
如果有“實例方法”,一定也會有其它類型的方法,對吧?是的,確實有,但這些方法有些深奧。我們會在這里簡略的介紹一下,但是可以更深入的研究這些主題。
靜態(tài)方法
類屬性是在類級別上設(shè)置的屬性,相對的是實例級別。普通屬性在<font color=red>__init__
</font>方法中引入,但有些屬性適用于所有實例。例如,思考下面<font color=red>Car
</font>對象的定義:
class Car(object):
wheels = 4
def __init__(self, make, model):
self.make = make
self.model = model
mustang = Car('Ford', 'Mustang')
print mustang.wheels
# 4
print Car.wheels
# 4
不管<font color=red>make
</font>和<font color=red>model
</font>是什么,一輛<font color=red>Car
</font>總是有四個<font color=red>Wheels
</font>。實例方法可以通過跟訪問普通屬性一樣訪問這些屬性:通過<font color=red>self
</font>(比如,<font color=red>self.wheels
</font>)。
有一種稱為靜態(tài)方法的方法,它們不能訪問<font color=red>self
</font>。跟類屬性類似,它們不需要實例就能工作。因為實例總是通過<font color=red>self
</font>引用,所以靜態(tài)方法沒有<font color=red>self
</font>參數(shù)。
下面是<font color=red>Car
</font>類的一個有效的靜態(tài)方法:
class Car(object):
...
def make_car_sound():
print 'VRooooommmm!'
不管我們擁有什么類型的汽車,它總是發(fā)出相同的聲音。為了說明這個方法不應(yīng)該接收實例作為第一個參數(shù)(比如“普通”方法的<font color=red>self
</font>),可以使用<font color=red>@staticmethod
</font>裝飾器,把我們的定義變成:
class Car(object):
...
@staticmethod
def make_car_sound():
print 'VRooooommmm!'
類方法
靜態(tài)方法的一個變種是類方法。它傳遞類,而不是實例作為第一個參數(shù)。它也使用裝飾器定義:
class Vehicle(object):
...
@classmethod
def is_motorcycle(cls):
return cls.wheels == 2
現(xiàn)在類方法可能沒有太大的意義,但它通常與下一個主題聯(lián)系在一起:繼承。
繼承
面向?qū)ο缶幊套鳛榻9ぞ叻浅S杏茫?strong>繼承的概念后,它真正變強(qiáng)大了。
繼承是“子”類衍生“父”類的數(shù)據(jù)和行為的過程。有一個實例可以明確的幫助我們理解。
想象我們經(jīng)營了一家汽車銷售店。我們銷售所有類型的車輛,從摩托車到卡車。我們通過價格與競爭對手區(qū)分開來。特別是我們?nèi)绾未_定車輛的價格:$5000 * 一臺車輛擁有的車輪數(shù)。我們也喜歡回購車輛。我們提供統(tǒng)一的價格 - 車輛行駛里程的10%。卡車的價格是$10,000,汽車是$8,000,摩托車是$4,000。
如果我們想用面對對象技術(shù)為汽車銷售店創(chuàng)建一個銷售系統(tǒng),應(yīng)該怎么做?對象是什么?我們可能有一個<font color=red>Sale
</font>類,一個<font color=red>Customer
</font>類,一個<font color=red>Inventor
</font>類等等,但我們肯定有一個<font color=red>Car
</font>,<font color=red>Truck
</font>和<font color=red>Motorcycle
</font>類。
這些類應(yīng)該是什么樣的?用我們已經(jīng)學(xué)會的知識,以下是<font color=red>Car
</font>類的一種實現(xiàn):
class Car(object):
"""A car for sale by Jeffco Car Dealership.
Attributes:
wheels: An integer representing the number of wheels the car has.
miles: The integral number of miles driven on the car.
make: The make of the car as a string.
model: The model of the car as a string.
year: The integral year the car was built.
sold_on: The date the vehicle was sold.
"""
def __init__(self, wheels, miles, make, model, year, sold_on):
"""Return a new Car object."""
self.wheels = wheels
self.miles = miles
self.make = make
self.model = model
self.year = year
self.sold_on = sold_on
def sale_price(self):
"""Return the sale price for this car as a float amount."""
if self.sold_on is not None:
return 0.0 # Already sold
return 5000.0 * self.wheels
def purchase_price(self):
"""Return the price for which we would pay to purchase the car."""
if self.sold_on is None:
return 0.0 # Not yet sold
return 8000 - (.10 * self.miles)
...
看起來非常合理。當(dāng)然,類中可能還有其它方法,但我已經(jīng)展示了兩個我們感興趣的方法:<font color=red>sale_price
</font>和<font color=red>purchase_price
</font>。我們之后會看到為什么這些很重要。
我們已經(jīng)有了<font color=red>Car
</font>類,也許我們應(yīng)該創(chuàng)建<font color=red>Truck
</font>類。我們按同樣的方式創(chuàng)建:
class Truck(object):
"""A truck for sale by Jeffco Car Dealership.
Attributes:
wheels: An integer representing the number of wheels the truck has.
miles: The integral number of miles driven on the truck.
make: The make of the truck as a string.
model: The model of the truck as a string.
year: The integral year the truck was built.
sold_on: The date the vehicle was sold.
"""
def __init__(self, wheels, miles, make, model, year, sold_on):
"""Return a new Truck object."""
self.wheels = wheels
self.miles = miles
self.make = make
self.model = model
self.year = year
self.sold_on = sold_on
def sale_price(self):
"""Return the sale price for this truck as a float amount."""
if self.sold_on is not None:
return 0.0 # Already sold
return 5000.0 * self.wheels
def purchase_price(self):
"""Return the price for which we would pay to purchase the truck."""
if self.sold_on is None:
return 0.0 # Not yet sold
return 10000 - (.10 * self.miles)
...
幾乎跟<font color=red>Car
</font>類一模一樣。編程中最重要的原則之一(通常不只是處理對象時)是“DRY”或者“Don't Repeat Yourself”。確定無疑,我們在這里重復(fù)了。實際上,<font color=red>Car
</font>類和<font color=red>Truck
</font>類只有一個字符不同(除了注釋)。
出什么事了?我們哪里做錯了?我們的主要問題是我們直奔概念:<font color=red>Car
</font>和<font color=red>Truck
</font>是真實的事物,直覺讓有形的對象成為類。但是它們共享這么多數(shù)據(jù)和功能,似乎我們可以在這里引入一個抽象。沒錯,它就是<font color=red>Vehicle
</font>。
抽象類
<font color=red>Vehicle
</font>不是真實世界的對象。而是一個概念,它包含某些真實世界中的對象(比如汽車,卡車和摩托車)。我們可以用這個事實來移除重復(fù)代碼,即每個對象都被看做是一臺車輛。通過定義<font color=red>Vehicle
</font>類達(dá)到目的:
class Vehicle(object):
"""A vehicle for sale by Jeffco Car Dealership.
Attributes:
wheels: An integer representing the number of wheels the vehicle has.
miles: The integral number of miles driven on the vehicle.
make: The make of the vehicle as a string.
model: The model of the vehicle as a string.
year: The integral year the vehicle was built.
sold_on: The date the vehicle was sold.
"""
base_sale_price = 0
def __init__(self, wheels, miles, make, model, year, sold_on):
"""Return a new Vehicle object."""
self.wheels = wheels
self.miles = miles
self.make = make
self.model = model
self.year = year
self.sold_on = sold_on
def sale_price(self):
"""Return the sale price for this vehicle as a float amount."""
if self.sold_on is not None:
return 0.0 # Already sold
return 5000.0 * self.wheels
def purchase_price(self):
"""Return the price for which we would pay to purchase the vehicle."""
if self.sold_on is None:
return 0.0 # Not yet sold
return self.base_sale_price - (.10 * self.miles)
通過替換<font color=red>class Car(object)
</font>中的<font color=red>object
</font>,我們可以讓<font color=red>Car
</font>和<font color=red>Truck
</font>類繼承<font color=red>Vehicle
</font>類。括號中的類表示從哪個類繼承(<font color=red>object
</font>實際上是“沒有繼承”。我們一會兒討論為什么這么寫)。
現(xiàn)在我們可以直截了當(dāng)?shù)亩x<font color=red>Car
</font>和<font color=red>Truck
</font>:
class Car(Vehicle):
def __init__(self, wheels, miles, make, model, year, sold_on):
"""Return a new Car object."""
self.wheels = wheels
self.miles = miles
self.make = make
self.model = model
self.year = year
self.sold_on = sold_on
self.base_sale_price = 8000
class Truck(Vehicle):
def __init__(self, wheels, miles, make, model, year, sold_on):
"""Return a new Truck object."""
self.wheels = wheels
self.miles = miles
self.make = make
self.model = model
self.year = year
self.sold_on = sold_on
self.base_sale_price = 10000
這樣可以工作了,但還有一些問題。首先我們?nèi)匀挥泻芏嘀貜?fù)的代碼。最終我們會處理完所有重復(fù)的代碼。其次,更大的問題是,我們引入了<font color=red>Vehicle
</font>類,但我們真的允許調(diào)用者創(chuàng)建<font color=red>Vehicle
</font>對象(而不是<font color=red>Car
</font>和<font color=red>Truck
</font>)?<font color=red>Vehicle
</font>僅僅是一個概念,不是真實的事物,所以下面代碼的意義是:
v = Vehicle(4, 0, 'Honda', 'Accord', 2014, None)
print v.purchase_price()
<font color=red>Vehicle
</font>沒有<font color=red>base_sale_price
</font>,只有各個子類(比如<font color=red>Car
</font>和<font color=red>Truck
</font>)有。問題在于<font color=red>Vehicle
</font>應(yīng)該是一個Abstract Base Class。Abstract Base Class是只可以被繼承的類;不能創(chuàng)建ABC的實例。這意味著如果<font color=red>Vehicle
</font>是一個ABC,那么下面的代碼就是非法的:
v = Vehicle(4, 0, 'Honda', 'Accord', 2014, None)
禁止這一點是有意義的,因為我們從來不會直接使用<font color=red>Vehicle
</font>。我們只想用它抽取一些通用的數(shù)據(jù)和行為。我們?nèi)绾巫屢粋€類成為ABC?很簡單!<font color=red>abc
</font>模塊包括一個稱為<font color=red>ABCMeta
</font>的元類。設(shè)置一個類的元類為<font color=red>ABCMeta
</font>,并讓其中一個方法為虛擬的,就能讓類成為一個ABC。ABC規(guī)定,虛擬方法必須在子類中存在,但不是必須要實現(xiàn)。例如,<font color=red>Vehicle
</font>類可以如下定義:
from abc import ABCMeta, abstractmethod
class Vehicle(object):
"""A vehicle for sale by Jeffco Car Dealership.
Attributes:
wheels: An integer representing the number of wheels the vehicle has.
miles: The integral number of miles driven on the vehicle.
make: The make of the vehicle as a string.
model: The model of the vehicle as a string.
year: The integral year the vehicle was built.
sold_on: The date the vehicle was sold.
"""
__metaclass__ = ABCMeta
base_sale_price = 0
def sale_price(self):
"""Return the sale price for this vehicle as a float amount."""
if self.sold_on is not None:
return 0.0 # Already sold
return 5000.0 * self.wheels
def purchase_price(self):
"""Return the price for which we would pay to purchase the vehicle."""
if self.sold_on is None:
return 0.0 # Not yet sold
return self.base_sale_price - (.10 * self.miles)
@abstractmethod
def vehicle_type():
""""Return a string representing the type of vehicle this is."""
pass
因為<font color=red>vehicle_type
</font>是一個<font color=red>abstractmethod
</font>,所以我們不能直接創(chuàng)建<font color=red>Vehicle
</font>實例。只要<font color=red>Car
</font>和<font color=red>Truck
</font>從<font color=red>Vehicle
</font>繼承,并定義了<font color=red>vehicle_type
</font>,我們就能實例化這些類。
返回<font color=red>Car
</font>類和<font color=red>Truck
</font>類中的重復(fù)代碼,看看我們是否可以把通用的功能提升到基類<font color=red>Vehicle
</font>中:
from abc import ABCMeta, abstractmethod
class Vehicle(object):
"""A vehicle for sale by Jeffco Car Dealership.
Attributes:
wheels: An integer representing the number of wheels the vehicle has.
miles: The integral number of miles driven on the vehicle.
make: The make of the vehicle as a string.
model: The model of the vehicle as a string.
year: The integral year the vehicle was built.
sold_on: The date the vehicle was sold.
"""
__metaclass__ = ABCMeta
base_sale_price = 0
wheels = 0
def __init__(self, miles, make, model, year, sold_on):
self.miles = miles
self.make = make
self.model = model
self.year = year
self.sold_on = sold_on
def sale_price(self):
"""Return the sale price for this vehicle as a float amount."""
if self.sold_on is not None:
return 0.0 # Already sold
return 5000.0 * self.wheels
def purchase_price(self):
"""Return the price for which we would pay to purchase the vehicle."""
if self.sold_on is None:
return 0.0 # Not yet sold
return self.base_sale_price - (.10 * self.miles)
@abstractmethod
def vehicle_type(self):
""""Return a string representing the type of vehicle this is."""
pass
現(xiàn)在<font color=red>Car
</font>和<font color=red>Truck
</font>類變成:
class Car(Vehicle):
"""A car for sale by Jeffco Car Dealership."""
base_sale_price = 8000
wheels = 4
def vehicle_type(self):
""""Return a string representing the type of vehicle this is."""
return 'car'
class Truck(Vehicle):
"""A truck for sale by Jeffco Car Dealership."""
base_sale_price = 10000
wheels = 4
def vehicle_type(self):
""""Return a string representing the type of vehicle this is."""
return 'truck'
這完全符合我們的直覺:就我們的系統(tǒng)而言,汽車和卡車之間的唯一區(qū)別是基礎(chǔ)售價。
定義一個<font color=red>Motocycle
</font>類非常簡單:
class Motorcycle(Vehicle):
"""A motorcycle for sale by Jeffco Car Dealership."""
base_sale_price = 4000
wheels = 2
def vehicle_type(self):
""""Return a string representing the type of vehicle this is."""
return 'motorcycle'
繼承和LSP
盡管看起來我們用繼承處理了重復(fù),但我們真正做的是簡單的提供適當(dāng)級別的抽象。抽象是理解繼承的關(guān)鍵。我們已經(jīng)看到使用繼承的一個附帶作用是減少重復(fù)的代碼,但從調(diào)用者的角度來看呢?使用繼承如何改變代碼?
事實證明有一點。想象我們有兩個類:<font color=red>Dog
</font>和<font color=red>Person
</font>,我們想寫一個函數(shù),它接收任何兩種對象類型,并打印該實例是否可以說話(狗不能,人可以)。我們可能這么編寫代碼:
def can_speak(animal):
if isinstance(animal, Person):
return True
elif isinstance(animal, Dog):
return False
else:
raise RuntimeError('Unknown animal!')
只有兩種類型的動物時沒問題,但是如何有20種呢,或者200種?那么<font color=red>if...elif
</font>會相當(dāng)長。
這里關(guān)鍵是<font color=red>can_speak
</font>不應(yīng)該關(guān)心處理的動物類型,動物類本身應(yīng)該告訴我們它能否說話。通過引入基類<font color=red>Animal
</font>,其中定義<font color=red>can_speak
</font>,可以避免函數(shù)的類型檢查。只要知道是傳進(jìn)來的是<font color=red>Animal
</font>,確定能否說話很簡單:
def can_speak(animal):
return animal.can_speak()
這是因為<font color=red>Person
</font>和<font color=red>Dog
</font>(或者其它任何從<font color=red>Animal
</font>繼承的類)遵循Liskov Substitution Principle。這表示我們可以在希望父類(<font color=red>Animal
</font>)的地方,使用子類(比如<font color=red>Person
</font>或<font color=red>Dog
</font>)替換。這聽起來很簡單,但它是interface的基礎(chǔ)。
總結(jié)
希望你們學(xué)會了什么是Python類,為什么它們很有用,以及如何使用。類和面向?qū)ο缶幊毯苌願W。確實,它涉及計算機(jī)科學(xué)的核心。本文不是對類的詳細(xì)研究,也不應(yīng)該是你的唯一參考。網(wǎng)絡(luò)上有數(shù)以千計的OOP和類的解釋,如果本文對你不合適,搜索會讓你找到更適合你的。
一如既往,歡迎在評論中更正和討論。只要保持禮貌就行。