iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Python

初學者的 30 天 Python 復健課程系列 第 27

復健第二十七天:學到現在只為搞懂這一刻的類別 Class 與物件 Object

  • 分享至 

  • xImage
  •  

從這個 Python 復健系列的開始,我們便不停地提及「物件 Object」這個字詞,因為 Python 是一個物件導向 object-oriented 的程式語言,會這麼稱呼的原因,也是因為 Python 中的每一樣東西都是物件,而物件擁有自己的「屬性 property 和方法 method」。

物件在哪裡?

除了使用 Python 本身內建的類別,我們可以也可以自己創建類別來建立出更多物件,因此我們可以想像類別就像是物件的建構器 constructor,用現實生活做舉例,建構器可以當作是蓋房子的藍圖。而當我們實例化 instantiate 一個類別時,則可以當作我們依照這個藍圖建造出一個房子,透過實例化,我們創建許多擁有相同屬性與方法的物件。

讓我重新再複習一次前面這串過多的資訊:「我們透過類別 class 定義物件的屬性和方法,而物件則代表這個類別的實例 instance。

好笑的是,雖然前面這段看起來很複雜,可是從一開始進入 Python 的復健旅程裡,我們在不知不覺中開始使用起類別與物件,讓我們來驗證這一點:

像數字、字串、串列、字典、元組、集合等各種資料類型,在程式中都是對應著 Python 內建類別的物件。例如我們創建一個變數 name 並賦值字串 'Frank' 也就是 name = 'Frank',接著我們使用 print(type(name))印出 name 的種類,會得到 <class 'str'>,發現了嗎?字串 'str 實際上也是一種「類別 class」。

Python 3.9.6 (default, Jun 28 2021, 15:26:21)
[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> num = 10
>>> type(num)
<class 'int'>
>>> string = 'string'
>>> type(string)
<class 'str'>
>>> boolean = True
>>> type(boolean)
<class 'bool'>
>>> lst = []
>>> type(lst)
<class 'list'>
>>> tpl = ()
>>> type(tpl)
<class 'tuple'>
>>> set1 = set()
>>> type(set1)
<class 'set'>
>>> dct = {}
>>> type(dct)
<class 'dict'>

如何創建新的類別?

要自己創建類別,我們需要使用關鍵字 class,後面接著類別名稱冒號,和變數命名不同的是,類別名稱的命名慣例不是使用蛇式命名,而是使用大駝峰命名法 Upper Camal Case 又稱作 Pascal Case

# 語法
class ClassName:
  代碼寫在這裡

讓我們實際寫一串 Python 程式碼:

class Person:
  pass
print(Person) # <class '__main__.Person'>

創建物件

在先前有說過,類別像是一張藍圖,如果要使用這張藍圖建立出一棟建築物(指的是 Python 中的 object 物件),這個動作叫做「實例化 instantiate」,我們可以通過實例化類別來創建物件。

p = Person()
print(p) # <__main__.Person object at 0x102c146e0>

從上述輸出的結果可以看出,p 是一個 object 類別。

類別建構函式

在上一個的範例裡面,我們用 Person 類別創建了一個物件。但是,沒有建構函式 class constructor 的類別在實際生活中幾乎沒有用處,有點像是一張只寫了建案名稱,卻忘記畫建物細節的藍圖,無法蓋出具有實質意義的東西。

因此我們需要使用建構函式來讓類別更加有用,在 Python 中有一個內建的 init() 建構函式。這個建構函式包含一個名為 self 的參數,這邊可以當作是「我自己 self」的意思,它是一個對當前類別實例的引用,如果有一點難理解的話,可以先用硬記的方式,self 可以當作是「實例化後的物件本身」,後面會慢慢理解它的語意。(相信我!)

讓我們繼續剛剛 Person 的範例:

class Person:
      def __init__(self, name):
          self.name = name  # self 允許將參數附加到類別

p = Person('Frank')
print(p.name) # Frank
print(p) # <__main__.Person object at 0x2abf46907e80>

所以這邊的 self 就是 pself.name 代表這個類別有一個 name 的屬性,該 name 屬性裡面的值,則是帶入因為參數 name 所得到的值。

對於初學者最困難的是,一開始會以為這三個 name 指的是同一個東西,但實際上應該是這樣:

class Person:
    def __init__(self, 姓名):
        self.name = 姓名

只有「姓名」那兩個地方指的 name 是同一個東西,而 self.name 則像是一個欄位,等著我們把「姓名」填入。

如果理解了上面的概念,這樣下面這一串應該也就非常易懂:

class Person:
      def __init__(self, firstname, lastname, age, country, city):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city

p = Person('Chien', 'Chuan', 40, 'Taiwan', 'Taipei')
print(p.firstname) # Chien
print(p.lastname) # Chuan
print(p.age) # 40
print(p.country) # Taiwan
print(p.city) # Taipei

物件方法

還記得串列、字串等這些類別都有自己的方法嗎?我們也可以在類別裡定義好這些方法 method,一旦這個類別透過物件實例化後,物件就可以使用這些方法,這些方法 method 屬於物件的函式 function。換句話說,所有的方法都是函式,但函式不一定能稱作方法,因為我們也可以單獨定義一個函式,而這些單獨被定義的函式就不會被稱作方法。

一樣來看程式碼:

class Person:
      def __init__(self, firstname, lastname, age, country, city):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city

      def person_info(self):
        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}'

p = Person('Chien', 'Chuan', 40, 'Taiwan', 'Taipei')
print(p.person_info()) # Chien Chuan is 40 years old. He lives in Taipei, Taiwan 

預設值方法

有時候,我們可能會希望物件的方法有預設值,所以如果我們在建構函式中為參數設置了預設值,那當我們在沒有放入引數的情況下實例化類別時,不會產生錯誤。

讓我們修改一下先前的程式碼:

class Person:
      def __init__(self, firstname='Frank', lastname='Jones', age=250, country='USA', city='Chicago'):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city

      def person_info(self):
        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.'

# 未傳入任何引數
p1 = Person()
print(p1.person_info()) # Frank Jones is 250 years old. He lives in Chicago, USA.

# 傳入引數
p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city') 
print(p2.person_info()) # John Doe is 30 years old. He lives in Noman city, Nomanland.

上一篇
復健第二十六天:可能聽不懂但會用就還好的裝飾器 decorator
下一篇
復健第二十八天:爸爸有的我也都有,類別的繼承
系列文
初學者的 30 天 Python 復健課程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言