Python Object And Classes
對象是 Python 語言的構建塊Python 很容易學習。然而,它有一些更難理解的方面,比如類和對象的世界。在本文中,你将學到:
通過揭開 Python 對象的神秘面紗,你對該語言的理解将大大增加!
對象對象在 Python 中起着核心作用。讓我們深入了解一下,以增加你對對象的理解。
你可能知道内置len函數。它返回你給它的對象的長度。但是,比如說,數字5 的長度是多少?讓我們運行一下代碼看看。
print(len(5))
我喜歡錯誤,因為它們說明了 Python 内部是如何工作的。在這種情況下,Python 告訴我們 5 是一個對象,它沒有len().
在 Python 中,一切都是對象。字符串、布爾值、數字,甚至函數都是對象。
我們可以使用内置函數檢查 REPL 中的對象dir()。當我們嘗試dir使用數字 5 時,它會顯示一個很大的函數列表,這些函數是任何數字對象的一部分
dir(5)
該列表以這些包含下劃線的奇怪命名函數開頭,例如__add__. 這些被稱為魔術方法,或 dunder(雙下劃線的縮寫)方法。
如果你仔細觀察,你會發現類型對象沒有__len__dunder 方法int。這就是 Python 的len()函數如何知道數字沒有長度的方式。len()所做的就是調用你提供的對象上的方法__len__()。這也是 Python 抱怨 'int' 類型的對象沒有len().
我在這裡随便介紹了方法這個詞。讓我更正式地定義它:
當函數是對象的一部分時,我們稱其為方法。
所以如果一個字符串确實有長度,它一定有一個__len__方法,對吧?讓我們來了解一下!
dir("test")
可以看到字符串有__len__()這個方法。由于這是一個方法,我們也可以調用它:
"test".__len__()
# 4
這相當于len("test"),但不那麼優雅。所以不要這樣做,這隻是為了說明這些東西是如何工作的。
還有一系列其他不那麼神奇的方法dir()向我們揭示了。随意嘗試一些,例如
"test".islower()
# true
此方法檢查整個字符串是否為小寫,因此 Python 返回 boolean True。其中一些方法需要一個或多個參數,例如replace:
"abcd".replace('a','b') # 它将所有出現的“a”替換為“b”。
# 'bbcd'
現在我們已經使用了對象并且知道 Python 中的一切都是對象,是時候定義對象是什麼了:
對象是數據(變量)和對該數據進行操作的方法的集合
對象和面向對象編程是 1990 年代初流行的概念。早期的計算機語言,如 C,沒有對象的概念。然而,事實證明,對象對于人類來說是一種易于理解的範式——它可以用來模拟許多現實生活中的情況。
如今,大多數(如果不是全部)新語言都有對象的概念。因此,你将要學習的内容在概念上也适用于其他語言。
由于對象是 Python 語言的構建塊,因此你也可以自己創建對象是合乎邏輯的。為此,我們需要先定義一個類。
class如果要創建自己的對象類型,首先需要定義它具有哪些方法以及它可以保存哪些數據。這個藍圖被稱為一個類
類是對象的藍圖
所有對象都基于一個類。當我們創建一個對象時,我們稱之為“創建一個類的實例”。字符串、數字甚至布爾值也是類的實例。讓我們用内置函數來探索type:
>>> type('a')
<class 'str'>
>>> type(1)
<class 'int'>
type(True)
<class 'bool'>
顯然我們看到一些有名為str、int和的類bool。這些是 Python 的一些原生類,但我們也可以構建自己的類!
讓我們創建一個代表汽車的類。
class Car:
speed = 0
started = False
def start(self):
self.started = True
print("Car started, let's ride!")
def increase_speed(self, delta):
if self.started:
self.speed = self. speed delta
print('Vrooooom!')
else:
print("你需要先啟動汽車")
def stop(self):
self.speed = 0
print('Halting')
讓我們首先創建并使用一個 Car 類型的對象
car = Car()
car.increase_speed(10)
car.start()
car.increase_speed(40)
對象始終是類的實例。一個類可以有多個實例。我們剛剛創建了一個 Car 類的實例,使用Car(),并将其分配給變量car。創建一個實例看起來就像調用一個函數——你稍後會知道為什麼。
接下來,我們在汽車對象上調用其中一種方法:嘗試在它還沒有啟動的時候提高它的速度。哎呀!隻有啟動汽車後,我們才能提高它的速度并享受它發出的噪音。
現在讓我們逐步回顧一下我們的 Car 類:
在這些方法的定義中,我們遇到了一些特殊的情況:它們都有一個參數,稱為self它們的第一個參數。
什麼是self?老實說,如果你問我,這是 Python 不太優雅的語言結構之一。
還記得我們在汽車對象上調用方法的時候car.start()嗎?我們不必傳遞self變量,即使在類内部start定義start(self)。
這就是正在發生的事情:
因此,僅在類定義中,我們使用 self 來引用屬于實例一部分的變量。要修改started屬于我們類的變量,我們使用self.started而不僅僅是started.
通過使用self,可以清楚地表明我們正在對作為此實例一部分的變量進行操作,而不是在對象外部定義并且恰好具有相同名稱的其他變量。
從一個類創建多個對象由于一個類隻是一個藍圖,你可以使用它來創建多個對象,就像你可以構建多個外觀相同的汽車一樣。它們的行為都相似,但它們都有自己的數據,而不是在對象之間共享:
>>> car1 = Car()
>>> car2 = Car()
>>> id(car1)
139771129539104
>>> id(car2)
139771129539160
我們在這裡創建了兩個汽車對象,car1 和 car2,并使用内置方法id()獲取它們的 id。Python 中的每個對象都有一個唯一的标識符,所以我們隻是證明了我們從同一個類中創建了兩個不同的對象。我們可以獨立使用它們:
>>> car1.start()
車子啟動了,我們騎吧!
>>> car1.increase_speed(10)
'Vrooom!'
>>> car1.speed
10
>>> car2.speed
0
我們剛剛開始car1并增加了它的速度,而car2的速度沒有發生改變,這就是不同的實例具有不同的狀态。
構造函數當從一個類創建一個對象時,看起來我們正在調用一個函數:
car = car()
但它看起來不僅僅是我們在調用一個函數,我們實際上是在調用一個函數!這個我們不必定義的方法稱為構造函數。它構造并初始化對象。每個類默認都有一個,稱為__init__,即使我們自己沒有定義它。這與繼承有關,稍後我将說明這一點。
你是否曾經使用該str()函數将對象轉換為類?或者可能是 int() 函數将字符串轉換為數字?
>>> 'a' str(1)
'a1'
>>> int('2') 2
4
實際上在這裡所做的是創建新的類型對象str并int通過調用類的構造函數str和int.
我們也可以重寫該__init__方法,通過接受參數來賦予它額外的能力。讓我們使用自定義構造函數重新定義 Car 類:
class Car:
def __init__(self, started = False, speed = 0):
self.started = started
self.speed = speed
def start(self):
self.started = True
print("Car started, let's ride!")
def increase_speed(self, delta):
if self.started:
self.speed = self.speed delta
print("Vrooooom!")
else:
print("你需要先啟動汽車")
def stop(self):
self.speed = 0
我們的自定義構造函數使用默認值命名參數,因此我們可以通過多種方式創建 Car 類的實例:
>>> c1 = Car()
>>> c2 = Car(True)
>>> c3 = Car(True, 50)
>>> c4 = Car(started=True, speed=40)
在編程中,盡可能多地重用代碼被認為是一種很好的風格。這種做法甚至有一個很好的首字母縮寫詞,稱為 DRY:不要重複自己。
類可以幫助你避免重複代碼,因為你可以編寫一個類并基于它創建許多對象。但是,它們還以另一種方式為你提供幫助,稱為繼承。類可以從其他類繼承屬性和函數,因此你不必重複自己。
例如,我們希望我們的 Car 類從 Vehicle 類繼承一些基礎知識。而且,當我們這樣做的時候,還要定義一個 Motorcycle 類。從示意圖上看,它看起來像這樣:
我們已經看到了繼承的作用。還記得我告訴過你每個類都有一個構造函數(__init__),即使你沒有定義一個?這是因為每個類都繼承自 Python 中最基本的類,稱為object:
dir(object)
當我告訴你“Python 中的一切都是對象”時,我的意思是一切。這包括類,如你所見,我們也可以dir()在類上使用。它表明object有一個__init__方法。
繼承映射到許多現實生活中的情況。讓我們根據上圖來看看實際的繼承。我們将從一個泛型Vehicle類開始:
class Vehicle:
def __init__(self, started = False, speed = 0):
self.started = started
self.speed = speed
def start(self):
self.started = True
print("Started, let's ride!")
def stop(self):
self.speed = 0
def increase_speed(self, delta):
if self.started:
self.speed = self.speed delta
print("Vrooooom!")
else:
print("You need to start me first")
現在我們可以Car使用繼承重新定義我們的類
class Car(Vehicle):
trunk_open = False
def open_trunk(self):
trunk_open = True
def close_trunk(self):
trunk_open = False
我們的汽車從類中繼承了所有的方法和變量Vehicle,但是增加了一個額外的變量和兩個方法。
重寫init方法有時你想覆蓋 init 函數。為了演示,我們可以創建一個 Motorcycle 類。大多數摩托車都有一個中心支架。我們将添加在初始化時将其輸出或輸入的功能:
class Motorcycle(Vehicle):
def __init__(self, center_stand_out = False):
self.center_stand_out = center_stand_out
super().__init__()
當你覆蓋構造函數時,根本不會調用來自父類(我們繼承的)的構造函數。如果你仍然需要該功能,則必須自己調用它。這是通過super():它返回對父類的引用,因此我們可以調用父類的構造函數。
在這種情況下,我們為中心支架添加了功能,但删除了在構造函數中設置速度和啟動狀态的選項。如果需要,你也可以添加速度和啟動狀态選項,并将它們傳遞給Vehicle構造函數。
覆蓋其他方法就像__init__,我們也可以覆蓋其他方法。例如,如果你想實現一個不啟動的摩托車,你可以重寫 start 方法:
class Motorcycle(Vehicle):
def __init__(self, center_stand_out = False):
self.center_stand_out = center_stand_out
super().__init__()
def start(self):
print("Sorry, out of fuel!")
感謝你的閱讀。如果你想了解有關 Python 的更多信息,請關注我。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!