如何通俗的理解面向?qū)ο缶幊?/h1>
點擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時間送達(dá)

本文轉(zhuǎn)自:磐創(chuàng)AI
面向?qū)ο缶幊袒騉OP對于初學(xué)者來說可能是一個很難理解的概念。這主要是因為很多地方都沒有正確的解釋。通常很多書籍都是從解釋OOP開始,討論三大術(shù)語:封裝、繼承和多態(tài)性。但是當(dāng)這本書能夠解釋這些話題的時候,任何一個剛剛開始的人都會感到失落。
所以,我想讓程序員、數(shù)據(jù)科學(xué)家和蟒蛇愛好者們更容易理解這個概念。我打算這樣做的方法是去掉所有的行話,并通過一些例子。我將從解釋類和對象開始。然后我將解釋為什么類在各種情況下都很重要,以及它們是如何解決一些基本問題的。這樣,讀者也能在帖子末尾理解這三大術(shù)語。
在這個名為Python Shorts的系列文章中,我將解釋Python提供的一些簡單但非常有用的構(gòu)造、一些基本技巧以及我在數(shù)據(jù)科學(xué)工作中經(jīng)常遇到的一些用例。
這篇文章是關(guān)于解釋OOP的外行方式。
什么是對象和類 簡單地說,Python中的一切都是對象,類是對象的藍(lán)圖。所以當(dāng)我們寫下:
a = 2
b = "Hello!"
我們正在創(chuàng)建一個int類的對象a,該對象的值為2,str類的對象b的值為“Hello!”. 當(dāng)我們在默認(rèn)情況下用兩個引號來提供字符串。
除此之外,我們中的許多人最終都會在沒有意識到的情況下使用類和對象。例如,當(dāng)你使用任何scikit-learn模型時,實際上是在使用一個類。
clf = RandomForestClassifier()
clf.fit(X,y)
這里的分類器clf是一個對象,fit是一個在RandomForestClassifier類中定義的方法
為什么要使用類 因此,我們在使用Python時經(jīng)常使用它們。但為什么呢。類是怎么回事?我可以用函數(shù)做同樣的事情嗎?
是的,你可以。但是與函數(shù)相比,類確實為你提供了很多功能。舉個例子,str類有很多為對象定義的函數(shù),我們只需按tab鍵就可以訪問這些函數(shù)。人們也可以編寫所有這些函數(shù),但是那樣的話,只按tab鍵就不能使用它們了。

類的這個屬性稱為封裝。從Wikipedia來看,封裝是指將數(shù)據(jù)與操作該數(shù)據(jù)的方法捆綁在一起,或者限制對對象某些組件的直接訪問。
所以這里str類綁定了數(shù)據(jù)(“Hello!)以及所有對我們的數(shù)據(jù)進(jìn)行操作的方法。我會在帖子的最后解釋聲明的第二部分。同樣,RandomForestClassifier 類將所有的方法(fit、predict等)捆綁在一起
除此之外,類的使用還可以幫助我們使代碼更加模塊化和易于維護(hù)。假設(shè)我們要創(chuàng)建一個像Scikit-Learn這樣的庫。我們需要創(chuàng)建許多模型,每個模型都有一個fit和predict方法。如果不使用類,我們將為每個不同的模型提供許多函數(shù),例如:
RFCFit
RFCPredict
SVCFit
SVCPredict
LRFit
LRPredict
and so on.
這種代碼結(jié)構(gòu)只是一場噩夢,因此Scikit Learn將每個模型定義為一個具有fit和predict方法的類。
創(chuàng)建類 所以,現(xiàn)在我們了解了為什么要使用類,它們是如何如此重要,我們?nèi)绾握嬲_始使用它們?所以,創(chuàng)建一個類非常簡單。下面是你將要編寫的任何類的樣板代碼:
class myClass:
def __init__(self, a, b):
self.a = a
self.b = b
def somefunc(self, arg1, arg2):
# 這里有些代碼
我們在這里看到很多新的關(guān)鍵字。主要是class、__init__和self。這些是什么?同樣,通過一些例子很容易解釋。
假設(shè)你在一家有很多賬戶的銀行工作。我們可以創(chuàng)建一個名為account的類,用于處理任何帳戶。例如,下面我創(chuàng)建了一個基本的玩具類帳戶,它為用戶存儲數(shù)據(jù),即帳戶名和余額。它還為我們提供了兩種銀行存款/取款的方法。一定要通讀一遍。它遵循與上面代碼相同的結(jié)構(gòu)。
class Account:
def __init__(self, account_name, balance=0):
self.account_name = account_name
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self,amount):
if amount <= self.balance:
self.balance -= amount
else:
print("Cannot Withdraw amounts as no funds!!!")
我們可以使用以下方法創(chuàng)建一個名為Rahul且金額為100的帳戶:
myAccount = Account("Rahul",100)
我們可以使用以下方法訪問此帳戶的數(shù)據(jù):

但是,如何將這些屬性balance和account_name分別設(shè)置為100和“Rahul”?我們從來沒有調(diào)用過__init__方法,那么為什么對象會獲得這些屬性?這里的答案是,只要我們創(chuàng)建對象,它就會運行。因此,當(dāng)我們創(chuàng)建myAccount時,它還會自動運行函數(shù)__init__
所以現(xiàn)在我們明白了,讓我們試著存一些錢到我們的賬戶里。我們可以通過:

我們的余額上升到200英鎊。但是你有沒有注意到,我們的函數(shù)deposit需要兩個參數(shù),即self和amount,但是我們只提供了一個參數(shù),而且仍然有效。
那么,這個self是什么?有self的方法是用一種不同的方式調(diào)用同一個函數(shù)。下面,我調(diào)用屬于類account的同一個函數(shù)deposit,并向它提供myAccount對象和amount?,F(xiàn)在函數(shù)需要兩個參數(shù)。

我們的賬戶余額如預(yù)期增加了100。所以這是我們調(diào)用的同一個函數(shù)。現(xiàn)在,只有self和myAccount是完全相同的對象時,才會發(fā)生這種情況。我調(diào)用的時候我的賬戶存款(100)。Python為函數(shù)調(diào)用提供與參數(shù)self相同的對象myAccount。這就是為什么self.balance在函數(shù)定義中真正指的是myAccount.balance.
但是,仍然存在一些問題

我們知道如何創(chuàng)建類,但是還有一個重要的問題我還沒有提到。
所以,假設(shè)你正在與蘋果iPhone部門合作,并且必須為每種iPhone型號創(chuàng)建一個不同的類。對于這個簡單的例子,讓我們假設(shè)我們的iPhone的第一個版本目前只做一件事——打電話并存儲。我們可以這樣寫:
class iPhone:
def __init__(self, memory, user_id):
self.memory = memory
self.mobile_id = user_id
def call(self, contactNum):
# 這里有些實現(xiàn)
現(xiàn)在,蘋果計劃推出iPhone1,這款iPhone機(jī)型引入了一項新功能——拍照功能。一種方法是復(fù)制粘貼上述代碼并創(chuàng)建一個新的類iPhone1,如下所示:
class iPhone1:
def __init__(self, memory, user_id):
self.memory = memory
self.mobile_id = user_id
self.pics = []
def call(self, contactNum):
# 這里有些實現(xiàn)
def click_pic(self):
# 這里有些實現(xiàn)
pic_taken = ...
self.pics.append(pic_taken)
但正如你所看到的,這是大量不必要的代碼重復(fù)(上面用粗體顯示),Python有一個消除代碼重復(fù)的解決方案。編寫iPhone1類的一個好方法是:
Class iPhone1(iPhone):
def __init__(self,memory,user_id):
super().__init__(memory,user_id)
self.pics = []
def click_pic(self):
# 這里有些實現(xiàn)
pic_taken = ...
self.pics.append(pic_taken)
這就是繼承的概念。根據(jù)Wikipedia的說法:繼承是將一個對象或類基于另一個保留類似實現(xiàn)的對象或類的機(jī)制。簡單地說,iPhone1現(xiàn)在可以訪問類iPhone中定義的所有變量和方法。
在本例中,我們不必進(jìn)行任何代碼復(fù)制,因為我們已經(jīng)從父類iPhone繼承(獲取)了所有方法。因此,我們不必再次定義調(diào)用函數(shù)。另外,我們不使用super在函數(shù)中設(shè)置mobile_uid和內(nèi)存。
**super().__init__(memory,user_id)**是什么?
在現(xiàn)實生活中,你的初始函數(shù)不是這些漂亮的兩行函數(shù)。你將需要在類中定義許多變量/屬性,并且復(fù)制并粘貼子類(這里是iphone1)會很麻煩。因此存在super().。這里super().__init__()實際上在這里調(diào)用父iPhone類的**__init__**方法。因此,在這里,當(dāng)類iPhone1的__init__函數(shù)運行時,它會自動使用父類的__init__函數(shù)設(shè)置類的memory和user_id。
我們在ML/DS/DL中的哪里可以看到?下面是我們創(chuàng)建PyTorch模型。此模型繼承了nn.Module類,并使用super調(diào)用該類的__init__函數(shù)。
class myNeuralNet(nn.Module):
def __init__(self):
super().__init__()
# 在這里定義所有層
self.lin1 = nn.Linear(784, 30)
self.lin2 = nn.Linear(30, 10)
def forward(self, x):
# 在此處連接層輸出以定義前向傳播
x = self.lin1(x)
x = self.lin2(x)
return x
但什么是「多態(tài)」?我們越來越了解類是如何工作的,所以我想我現(xiàn)在就試著解釋多態(tài)??聪旅娴念悺?/span>
import math
class Shape:
def __init__(self, name):
self.name = name
def area(self):
pass
def getName(self):
return self.name
class Rectangle(Shape):
def __init__(self, name, length, breadth):
super().__init__(name)
self.length = length
self.breadth = breadth
def area(self):
return self.length*self.breadth
class Square(Rectangle):
def __init__(self, name, side):
super().__init__(name,side,side)
class Circle(Shape):
def __init__(self, name, radius):
super().__init__(name)
self.radius = radius
def area(self):
return pi*self.radius**2
這里我們有基類Shape和其他派生類-Rectangle和Circle。另外,看看我們?nèi)绾卧赟quare類中使用多個級別的繼承,Square類是從Rectangle派生的,而Rectangle又是從Shape派生的。每個類都有一個名為area的函數(shù),它是根據(jù)形狀定義的。
因此,通過Python中的多態(tài)性,一個同名函數(shù)可以執(zhí)行多個任務(wù)的概念成為可能。事實上,這就是多態(tài)性的字面意思:“具有多種形式的東西”。所以這里我們的函數(shù)area有多種形式。
多態(tài)性與Python一起工作的另一種方式是使用isinstance方法。因此,使用上面的類,如果我們這樣做:

因此,對象mySquare的實例類型是方形、矩形和形狀。因此對象是多態(tài)的。這有很多好的特性。例如,我們可以創(chuàng)建一個與Shape對象一起工作的函數(shù),它將通過使用多態(tài)性完全處理任何派生類(Square、Circle、Rectangle等)。

更多信息 為什么我們看到函數(shù)名或?qū)傩悦詥蜗聞澗€和雙下劃線開頭?有時我們想讓類中的屬性和函數(shù)私有化,而不允許用戶看到它們。這是封裝的一部分,我們希望“限制對對象某些組件的直接訪問”。例如,假設(shè)我們不想讓用戶看到我們的iPhone創(chuàng)建后的memory(RAM)。在這種情況下,我們使用變量名中的下劃線創(chuàng)建屬性。
因此,當(dāng)我們以下面的方式創(chuàng)建iPhone類時,你將無法訪問你的memory或ipython私有函數(shù),因為該屬性現(xiàn)在使用_。

但你仍然可以使用(盡管不建議使用)更改變量值,

你還可以使用私有函數(shù)myphone._privatefunc()。如果要避免這種情況,可以在變量名前面使用雙下劃線。例如,在調(diào)用print(myphone.__memory)下面拋出一個錯誤。此外,你無法使用myphone更改對象的內(nèi)部數(shù)據(jù)。myphone.__memory = 1。

但是,正如你所見,你可以在類定義中的函數(shù)setMemory中訪問和修改self.__memory
結(jié)論 
我希望這對你理解類很有用。仍然有很多類需要我在下一篇關(guān)于magic方法的文章中討論。敬請期待。另外,總結(jié)一下,在這篇文章中,我們學(xué)習(xí)了OOP和創(chuàng)建類以及OOP的各種基礎(chǔ)知識:
封裝:對象包含自身的所有數(shù)據(jù)。
繼承:我們可以創(chuàng)建一個類層次結(jié)構(gòu),其中父類的方法傳遞給子類
多態(tài):函數(shù)有多種形式,或者對象可能有多種類型。
為了結(jié)束這篇文章,我會給你一個練習(xí),讓你去實現(xiàn),因為我認(rèn)為這可能會為你澄清一些概念。創(chuàng)建一個類,使你可以使用體積和曲面面積管理三維對象(球體和立方體)。基本樣板代碼如下所示:
import math
class Shape3d:
def __init__(self, name):
self.name = name
def surfaceArea(self):
pass
def volume(self):
pass
def getName(self):
return self.name
class Cuboid():
pass
class Cube():
pass
class Sphere():
pass
如果你想了解更多關(guān)于Python的知識,我想從密歇根大學(xué)(universityofmichigan)調(diào)出一門關(guān)于學(xué)習(xí)中級Python的優(yōu)秀課程:https://bit.ly/shrea
下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
在「小白學(xué)視覺」公眾號后臺回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺、目標(biāo)跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。
下載2:Python視覺實戰(zhàn)項目52講 在「小白學(xué)視覺」公眾號后臺回復(fù):Python視覺實戰(zhàn)項目,即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學(xué)校計算機(jī)視覺。
下載3:OpenCV實戰(zhàn)項目20講 在「小白學(xué)視覺」公眾號后臺回復(fù):OpenCV實戰(zhàn)項目20講,即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。
交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~
瀏覽
38
點擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時間送達(dá)
本文轉(zhuǎn)自:磐創(chuàng)AI
面向?qū)ο缶幊袒騉OP對于初學(xué)者來說可能是一個很難理解的概念。這主要是因為很多地方都沒有正確的解釋。通常很多書籍都是從解釋OOP開始,討論三大術(shù)語:封裝、繼承和多態(tài)性。但是當(dāng)這本書能夠解釋這些話題的時候,任何一個剛剛開始的人都會感到失落。
所以,我想讓程序員、數(shù)據(jù)科學(xué)家和蟒蛇愛好者們更容易理解這個概念。我打算這樣做的方法是去掉所有的行話,并通過一些例子。我將從解釋類和對象開始。然后我將解釋為什么類在各種情況下都很重要,以及它們是如何解決一些基本問題的。這樣,讀者也能在帖子末尾理解這三大術(shù)語。
在這個名為Python Shorts的系列文章中,我將解釋Python提供的一些簡單但非常有用的構(gòu)造、一些基本技巧以及我在數(shù)據(jù)科學(xué)工作中經(jīng)常遇到的一些用例。
這篇文章是關(guān)于解釋OOP的外行方式。
簡單地說,Python中的一切都是對象,類是對象的藍(lán)圖。所以當(dāng)我們寫下:
a = 2
b = "Hello!"
我們正在創(chuàng)建一個int類的對象a,該對象的值為2,str類的對象b的值為“Hello!”. 當(dāng)我們在默認(rèn)情況下用兩個引號來提供字符串。
除此之外,我們中的許多人最終都會在沒有意識到的情況下使用類和對象。例如,當(dāng)你使用任何scikit-learn模型時,實際上是在使用一個類。
clf = RandomForestClassifier()
clf.fit(X,y)
這里的分類器clf是一個對象,fit是一個在RandomForestClassifier類中定義的方法
因此,我們在使用Python時經(jīng)常使用它們。但為什么呢。類是怎么回事?我可以用函數(shù)做同樣的事情嗎?
是的,你可以。但是與函數(shù)相比,類確實為你提供了很多功能。舉個例子,str類有很多為對象定義的函數(shù),我們只需按tab鍵就可以訪問這些函數(shù)。人們也可以編寫所有這些函數(shù),但是那樣的話,只按tab鍵就不能使用它們了。

類的這個屬性稱為封裝。從Wikipedia來看,封裝是指將數(shù)據(jù)與操作該數(shù)據(jù)的方法捆綁在一起,或者限制對對象某些組件的直接訪問。
所以這里str類綁定了數(shù)據(jù)(“Hello!)以及所有對我們的數(shù)據(jù)進(jìn)行操作的方法。我會在帖子的最后解釋聲明的第二部分。同樣,RandomForestClassifier 類將所有的方法(fit、predict等)捆綁在一起
除此之外,類的使用還可以幫助我們使代碼更加模塊化和易于維護(hù)。假設(shè)我們要創(chuàng)建一個像Scikit-Learn這樣的庫。我們需要創(chuàng)建許多模型,每個模型都有一個fit和predict方法。如果不使用類,我們將為每個不同的模型提供許多函數(shù),例如:
RFCFit
RFCPredict
SVCFit
SVCPredict
LRFit
LRPredict
and so on.
這種代碼結(jié)構(gòu)只是一場噩夢,因此Scikit Learn將每個模型定義為一個具有fit和predict方法的類。
所以,現(xiàn)在我們了解了為什么要使用類,它們是如何如此重要,我們?nèi)绾握嬲_始使用它們?所以,創(chuàng)建一個類非常簡單。下面是你將要編寫的任何類的樣板代碼:
class myClass:
def __init__(self, a, b):
self.a = a
self.b = b
def somefunc(self, arg1, arg2):
# 這里有些代碼
我們在這里看到很多新的關(guān)鍵字。主要是class、__init__和self。這些是什么?同樣,通過一些例子很容易解釋。
假設(shè)你在一家有很多賬戶的銀行工作。我們可以創(chuàng)建一個名為account的類,用于處理任何帳戶。例如,下面我創(chuàng)建了一個基本的玩具類帳戶,它為用戶存儲數(shù)據(jù),即帳戶名和余額。它還為我們提供了兩種銀行存款/取款的方法。一定要通讀一遍。它遵循與上面代碼相同的結(jié)構(gòu)。
class Account:
def __init__(self, account_name, balance=0):
self.account_name = account_name
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self,amount):
if amount <= self.balance:
self.balance -= amount
else:
print("Cannot Withdraw amounts as no funds!!!")
我們可以使用以下方法創(chuàng)建一個名為Rahul且金額為100的帳戶:
myAccount = Account("Rahul",100)
我們可以使用以下方法訪問此帳戶的數(shù)據(jù):

但是,如何將這些屬性balance和account_name分別設(shè)置為100和“Rahul”?我們從來沒有調(diào)用過__init__方法,那么為什么對象會獲得這些屬性?這里的答案是,只要我們創(chuàng)建對象,它就會運行。因此,當(dāng)我們創(chuàng)建myAccount時,它還會自動運行函數(shù)__init__
所以現(xiàn)在我們明白了,讓我們試著存一些錢到我們的賬戶里。我們可以通過:

我們的余額上升到200英鎊。但是你有沒有注意到,我們的函數(shù)deposit需要兩個參數(shù),即self和amount,但是我們只提供了一個參數(shù),而且仍然有效。
那么,這個self是什么?有self的方法是用一種不同的方式調(diào)用同一個函數(shù)。下面,我調(diào)用屬于類account的同一個函數(shù)deposit,并向它提供myAccount對象和amount?,F(xiàn)在函數(shù)需要兩個參數(shù)。

我們的賬戶余額如預(yù)期增加了100。所以這是我們調(diào)用的同一個函數(shù)。現(xiàn)在,只有self和myAccount是完全相同的對象時,才會發(fā)生這種情況。我調(diào)用的時候我的賬戶存款(100)。Python為函數(shù)調(diào)用提供與參數(shù)self相同的對象myAccount。這就是為什么self.balance在函數(shù)定義中真正指的是myAccount.balance.
但是,仍然存在一些問題

我們知道如何創(chuàng)建類,但是還有一個重要的問題我還沒有提到。
所以,假設(shè)你正在與蘋果iPhone部門合作,并且必須為每種iPhone型號創(chuàng)建一個不同的類。對于這個簡單的例子,讓我們假設(shè)我們的iPhone的第一個版本目前只做一件事——打電話并存儲。我們可以這樣寫:
class iPhone:
def __init__(self, memory, user_id):
self.memory = memory
self.mobile_id = user_id
def call(self, contactNum):
# 這里有些實現(xiàn)
現(xiàn)在,蘋果計劃推出iPhone1,這款iPhone機(jī)型引入了一項新功能——拍照功能。一種方法是復(fù)制粘貼上述代碼并創(chuàng)建一個新的類iPhone1,如下所示:
class iPhone1:
def __init__(self, memory, user_id):
self.memory = memory
self.mobile_id = user_id
self.pics = []
def call(self, contactNum):
# 這里有些實現(xiàn)
def click_pic(self):
# 這里有些實現(xiàn)
pic_taken = ...
self.pics.append(pic_taken)
但正如你所看到的,這是大量不必要的代碼重復(fù)(上面用粗體顯示),Python有一個消除代碼重復(fù)的解決方案。編寫iPhone1類的一個好方法是:
Class iPhone1(iPhone):
def __init__(self,memory,user_id):
super().__init__(memory,user_id)
self.pics = []
def click_pic(self):
# 這里有些實現(xiàn)
pic_taken = ...
self.pics.append(pic_taken)
這就是繼承的概念。根據(jù)Wikipedia的說法:繼承是將一個對象或類基于另一個保留類似實現(xiàn)的對象或類的機(jī)制。簡單地說,iPhone1現(xiàn)在可以訪問類iPhone中定義的所有變量和方法。
在本例中,我們不必進(jìn)行任何代碼復(fù)制,因為我們已經(jīng)從父類iPhone繼承(獲取)了所有方法。因此,我們不必再次定義調(diào)用函數(shù)。另外,我們不使用super在函數(shù)中設(shè)置mobile_uid和內(nèi)存。
**super().__init__(memory,user_id)**是什么?
在現(xiàn)實生活中,你的初始函數(shù)不是這些漂亮的兩行函數(shù)。你將需要在類中定義許多變量/屬性,并且復(fù)制并粘貼子類(這里是iphone1)會很麻煩。因此存在super().。這里super().__init__()實際上在這里調(diào)用父iPhone類的**__init__**方法。因此,在這里,當(dāng)類iPhone1的__init__函數(shù)運行時,它會自動使用父類的__init__函數(shù)設(shè)置類的memory和user_id。
我們在ML/DS/DL中的哪里可以看到?下面是我們創(chuàng)建PyTorch模型。此模型繼承了nn.Module類,并使用super調(diào)用該類的__init__函數(shù)。
class myNeuralNet(nn.Module):
def __init__(self):
super().__init__()
# 在這里定義所有層
self.lin1 = nn.Linear(784, 30)
self.lin2 = nn.Linear(30, 10)
def forward(self, x):
# 在此處連接層輸出以定義前向傳播
x = self.lin1(x)
x = self.lin2(x)
return x
但什么是「多態(tài)」?我們越來越了解類是如何工作的,所以我想我現(xiàn)在就試著解釋多態(tài)??聪旅娴念悺?/span>
import math
class Shape:
def __init__(self, name):
self.name = name
def area(self):
pass
def getName(self):
return self.name
class Rectangle(Shape):
def __init__(self, name, length, breadth):
super().__init__(name)
self.length = length
self.breadth = breadth
def area(self):
return self.length*self.breadth
class Square(Rectangle):
def __init__(self, name, side):
super().__init__(name,side,side)
class Circle(Shape):
def __init__(self, name, radius):
super().__init__(name)
self.radius = radius
def area(self):
return pi*self.radius**2
這里我們有基類Shape和其他派生類-Rectangle和Circle。另外,看看我們?nèi)绾卧赟quare類中使用多個級別的繼承,Square類是從Rectangle派生的,而Rectangle又是從Shape派生的。每個類都有一個名為area的函數(shù),它是根據(jù)形狀定義的。
因此,通過Python中的多態(tài)性,一個同名函數(shù)可以執(zhí)行多個任務(wù)的概念成為可能。事實上,這就是多態(tài)性的字面意思:“具有多種形式的東西”。所以這里我們的函數(shù)area有多種形式。
多態(tài)性與Python一起工作的另一種方式是使用isinstance方法。因此,使用上面的類,如果我們這樣做:

因此,對象mySquare的實例類型是方形、矩形和形狀。因此對象是多態(tài)的。這有很多好的特性。例如,我們可以創(chuàng)建一個與Shape對象一起工作的函數(shù),它將通過使用多態(tài)性完全處理任何派生類(Square、Circle、Rectangle等)。

為什么我們看到函數(shù)名或?qū)傩悦詥蜗聞澗€和雙下劃線開頭?有時我們想讓類中的屬性和函數(shù)私有化,而不允許用戶看到它們。這是封裝的一部分,我們希望“限制對對象某些組件的直接訪問”。例如,假設(shè)我們不想讓用戶看到我們的iPhone創(chuàng)建后的memory(RAM)。在這種情況下,我們使用變量名中的下劃線創(chuàng)建屬性。
因此,當(dāng)我們以下面的方式創(chuàng)建iPhone類時,你將無法訪問你的memory或ipython私有函數(shù),因為該屬性現(xiàn)在使用_。

但你仍然可以使用(盡管不建議使用)更改變量值,

你還可以使用私有函數(shù)myphone._privatefunc()。如果要避免這種情況,可以在變量名前面使用雙下劃線。例如,在調(diào)用print(myphone.__memory)下面拋出一個錯誤。此外,你無法使用myphone更改對象的內(nèi)部數(shù)據(jù)。myphone.__memory = 1。

但是,正如你所見,你可以在類定義中的函數(shù)setMemory中訪問和修改self.__memory

我希望這對你理解類很有用。仍然有很多類需要我在下一篇關(guān)于magic方法的文章中討論。敬請期待。另外,總結(jié)一下,在這篇文章中,我們學(xué)習(xí)了OOP和創(chuàng)建類以及OOP的各種基礎(chǔ)知識:
封裝:對象包含自身的所有數(shù)據(jù)。
繼承:我們可以創(chuàng)建一個類層次結(jié)構(gòu),其中父類的方法傳遞給子類
多態(tài):函數(shù)有多種形式,或者對象可能有多種類型。
為了結(jié)束這篇文章,我會給你一個練習(xí),讓你去實現(xiàn),因為我認(rèn)為這可能會為你澄清一些概念。創(chuàng)建一個類,使你可以使用體積和曲面面積管理三維對象(球體和立方體)。基本樣板代碼如下所示:
import math
class Shape3d:
def __init__(self, name):
self.name = name
def surfaceArea(self):
pass
def volume(self):
pass
def getName(self):
return self.name
class Cuboid():
pass
class Cube():
pass
class Sphere():
pass
如果你想了解更多關(guān)于Python的知識,我想從密歇根大學(xué)(universityofmichigan)調(diào)出一門關(guān)于學(xué)習(xí)中級Python的優(yōu)秀課程:https://bit.ly/shrea
交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~
