跳到主要內容

Day 13 物件導向入門

Day 13 物件導向入門

引言

過去十二天,我們寫的都是函式導向的程式:用變數儲存資料、用函式處理資料,再用串列、字典把資料裝在一起。這種寫法在規模小的時候很直覺,但專案一長,函式之間的關係就會變得難以追蹤。光是要記住「哪些函式會改哪些變數」「哪些變數在哪個模組裡」就要花上不少心思,維護起來也容易踩到地雷。

物件導向(OOP)提供了另一種思路:把「資料」與「操作資料的函式」綁在一起,這個組合就稱為「物件」。學會這種寫法,程式碼會更像在描述真實世界的角色與行為,閱讀起來也更貼近自然語言。學物件導向不只是為了寫大型軟體,更是為了看懂接下來的 PyTorch 神經網路:PyTorch 把每一層神經網路定義成一個 class(類別),模型的每一層都是物件;如果你不懂 self、__init__ 與方法呼叫,看 PyTorch 模型程式碼會霧煞煞。今天先用簡單的生活範例把基礎打穩,明天再進到繼承與小專案。

類別與物件:class 的基本結構

類別(class)是物件的藍圖,物件(object)是類別的實例。可以把類別想成「房屋的設計圖」,把物件想成「依照設計圖蓋出來的每一棟房子」。在 Python 中定義類別非常簡單,使用 class 關鍵字即可。類別內的函式稱為方法(method),第一個參數慣例上命名為 self,代表「這個物件自己」。

class Dog:
    # 建構子:建立物件時自動執行
    def __init__(self, name, age):
        self.name = name  # 實例屬性
        self.age = age

    def bark(self):
        print(f"{self.name} 汪汪叫!")

    def introduce(self):
        print(f"我叫 {self.name},今年 {self.age} 歲")

# 建立物件
dog1 = Dog("小黑", 3)
dog1.bark()         # 輸出:小黑 汪汪叫!
dog1.introduce()    # 輸出:我叫 小黑,今年 3 歲

__init__ 是建構子,在建立物件時會自動呼叫,用來設定初始狀態。self.name = name 的意思是「把傳進來的參數 name 存到這個物件自己的 name 屬性」。呼叫方法時,dog1.bark() 其實是 Python 在幫我們把 dog1 傳給 bark 的 self 參數,所以即使定義時有 self,呼叫端不必再傳一次。這種「方法自動拿到自己」的設計,就是物件導向把資料與行為綁在一起的關鍵。

同一個類別可以建立多個物件,每個物件各自擁有自己的屬性。dog1.name 與 dog2.name 是兩個完全獨立的變數,修改其中一個不會影響到另一個。這種隔離讓我們能用同一個藍圖產出多個獨立個體,是模擬真實世界最直觀的方式。當一個程式需要同時處理多筆同性質的資料(例如 100 張訂單、1000 張圖片),這種設計就能讓我們用一致的介面操作每一筆資料,而不需為每筆單獨寫程式。

屬性:實例屬性與類別屬性

屬性(attribute)是儲存在物件裡的變數。剛剛看到的 self.name 是「實例屬性」,每個物件各自獨立。相對地,「類別屬性」則是所有物件共享的,放在類別內、方法外。類別屬性適合存放所有實例都相同的設定,例如物種、單位、預設值等。

class Dog:
    species = "Canis familiaris"  # 類別屬性,所有物件共享

    def __init__(self, name, age):
        self.name = name        # 實例屬性,每個物件獨立
        self.age = age

dog1 = Dog("小黑", 3)
dog2 = Dog("小白", 5)

print(dog1.species)  # 輸出:Canis familiaris
print(dog2.species)  # 輸出:Canis familiaris

dog1.age = 4         # 只影響 dog1
print(dog1.age)      # 輸出:4
print(dog2.age)      # 輸出:5

類別屬性可以透過類別本身或任一個物件存取,但只有從類別修改才會真正改變共享的值。如果用 dog1.species = "其他物種",其實是在 dog1 上「新增」一個實例屬性,把原本的類別屬性遮蔽起來,並沒有改到全體共享的值。如果之後想動態新增屬性,也可以直接 dog1.color = "black",不過建議一開始就在 __init__ 中定義完整,讓結構清楚、除錯時也比較容易找到欄位來源。實務上也建議把類別屬性集中在類別最上方,這樣閱讀程式的人能一眼看到所有物件共用的設定。

方法:實例方法、類別方法、靜態方法

方法(method)是定義在類別內的函式,依照用途可以分成三種。常見的是實例方法,第一個參數是 self,能存取物件的屬性。如果想操作整個類別而不是單一物件,可以用 @classmethod 裝飾,第一個參數是 cls。如果方法和類別、物件都沒關係,只是想歸類在一起,可以用 @staticmethod。

class Circle:
    pi = 3.14159

    def __init__(self, radius):
        self.radius = radius

    # 實例方法:用 self 存取物件屬性
    def area(self):
        return Circle.pi * self.radius ** 2

    # 類別方法:用 cls 存取類別屬性,常用來建立替代建構子
    @classmethod
    def from_diameter(cls, diameter):
        return cls(diameter / 2)

    # 靜態方法:不存取 self 或 cls,純函式
    @staticmethod
    def unit():
        return "cm"

c1 = Circle(5)
print(c1.area())              # 輸出:78.53975
c2 = Circle.from_diameter(10)
print(c2.radius)              # 輸出:5.0
print(Circle.unit())          # 輸出:cm

@classmethod 常用來做「替代建構子」,例如從字串、字典、檔案內容建立物件;@staticmethod 則像一般函式,只是為了組織程式碼而放在類別內。初學者先熟悉實例方法即可,後續兩種看專案需要再使用。當你開始看到別人的程式碼出現 @classmethod,第一直覺應該是「這是用來提供另一種建立物件的方式」,這對理解大型專案的設計會很有幫助。

特殊方法:__str__ 與 __repr__

當你 print 一個物件時,預設會顯示像 <__main__.Dog object at 0x000001> 這種沒什麼用的記憶體位址。透過定義 __str__ 與 __repr__ 這兩個特殊方法(dunder methods,因為名字前後各兩個底線),可以讓 print 與除錯輸出更友善。這些特殊方法會在特定場合被 Python 自動呼叫,是「物件與內建機制溝通」的標準介面。

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        # 給 print() 與 str() 使用
        return f"Dog(name={self.name}, age={self.age})"

    def __repr__(self):
        # 給除錯與互動式環境使用
        return f"Dog({self.name!r}, {self.age})"

dog = Dog("小黑", 3)
print(dog)       # 輸出:Dog(name=小黑, age=3)
print(repr(dog)) # 輸出:Dog('小黑', 3)

__str__ 偏向給一般使用者看,__repr__ 偏向給開發者除錯用,理想上 __repr__ 應該盡量像一段可執行的程式碼。除了這兩個,還有 __len__、__eq__、__getitem__ 等特殊方法,能讓物件支援 len()、== 比較、[i] 索引這些內建語法,是 Python 物件導向很重要的一環。等我們之後寫到 PyTorch 的自定義層時,就會用到 __call__ 讓物件可以像函式一樣被 invoke,這也是深度學習框架大量依賴的特殊方法機制。

結語

今天從最基本的 class、__init__、self 開始,建立物件導向的基礎觀念。我們了解到實例屬性與類別屬性的差別、三種方法的用途,以及透過 __str__、__repr__ 讓物件輸出更友善。物件導向的核心不是語法,而是「把資料與行為綁在一起」的思考方式,後續寫模型、寫工具都會用上。建議自己動手定義一個簡單的類別,例如 Notebook(記事本)或 Todo(待辦事項),把今天學到的屬性、方法、特殊方法都實際用過一次。動手寫過一次,會比只看文章更能體會 self 與物件狀態的存在感,也會發現實際呼叫時少了 self 反而會更直覺。

明天,我們會進一步學繼承、封裝與多型,再用這些觀念實作一個簡單的記帳小專案,順便為之後 PyTorch 的 nn.Module 鋪路。等你跟著進度寫完兩天,就會發現「類別 + 繼承」其實就是把生活裡的分類思考(動物→狗貓、記帳→收入/支出)直接映射到程式碼,沒有想像中那麼抽象。

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...