Python - 封裝:初學者指南

你好,未來的 Python 魔法師們!今天,我們將要深入探究封裝的神奇世界。如果這個詞聽起來像是《哈利波特》中的一個咒語,那也沒關係 - 在這堂課結束時,你將能夠像專家一樣運用這個概念!

Python - Encapsulation

什麼是封裝?

封裝就像擁有一本帶鎖的秘密日記。這是一種將數據(日記條目)和操作這些數據的方法(寫日記的行為)打包成一個單一單位的做法,同時也控制對這些數據的訪問。在 Python 中,我們使用類別來實現這一點。

讓我們從一個簡單的例子開始:

class Diary:
def __init__(self):
self.entries = []

def add_entry(self, entry):
self.entries.append(entry)

def get_entries(self):
return self.entries

my_diary = Diary()
my_diary.add_entry("親愛的日記,今天我學習了封裝!")
print(my_diary.get_entries())

在這個例子中,Diary是我們的類別。它有一個私有屬性entries(我們的秘密日記內容)和兩個與之交互的方法。這就是封裝的實際操作!

在 Python 中實現封裝

私有屬性

在 Python 中,我們使用一個慣例,即在屬性前加上底線來表示它們是私有的。讓我們更新我們的 Diary 類別:

class Diary:
def __init__(self):
self._entries = []  # 注意底線

def add_entry(self, entry):
self._entries.append(entry)

def get_entries(self):
return self._entries.copy()  # 返回副本以保護原始內容

my_diary = Diary()
my_diary.add_entry("我愛 Python!")
print(my_diary.get_entries())
# 這將會工作,但不推薦:
print(my_diary._entries)

底線告訴其他程式設計師:"嘿,這是私有的!不要直接碰它!"但是在 Python 中,這只是一個紳士協議 - 你仍然可以訪問它,但你不應該。

屬性裝飾器

為了獲得更多控制,我們可以使用屬性裝飾器。它們是我們屬性的神奇守衛:

class Diary:
def __init__(self):
self._entries = []

def add_entry(self, entry):
self._entries.append(entry)

@property
def entries(self):
return self._entries.copy()

my_diary = Diary()
my_diary.add_entry("屬性很酷!")
print(my_diary.entries)  # 這會工作
# my_diary.entries = []  # 這會引發錯誤

@property裝飾器允許我們像訪問屬性一樣訪問entries,但它實際上是在背後調用一個方法。這讓我們可以更控制數據的訪問方式。

設定器和獲取器

有時,我們希望允許對我們的屬性進行受控的修改。進入設定器:

class Diary:
def __init__(self):
self._entries = []

def add_entry(self, entry):
self._entries.append(entry)

@property
def entries(self):
return self._entries.copy()

@entries.setter
def entries(self, new_entries):
if isinstance(new_entries, list):
self._entries = new_entries
else:
raise ValueError("條目必須是列表")

my_diary = Diary()
my_diary.entries = ["第一天", "第二天"]  # 現在這會工作
print(my_diary.entries)
my_diary.entries = "不是列表"  # 這會引發錯誤

現在我們可以直接設定entries,但只有當它是列表時才可以。我們的日記變得非常複雜!

為什麼使用封裝?

  1. 數據保護:它防止了數據的意外修改。
  2. 靈活性:您可以更改內部實現而不影響外部代碼。
  3. 控制:您決定如何訪問和修改數據。

想象一下,如果任何人都可以在沒有您允許的情況下隨意在你的日記上亂寫 - 混亂!封裝保持事物有序和安全。

高級封裝技術

名稱重整

當你真的想保持事物的私有時,Python 提供了名稱重整:

class SuperSecretDiary:
def __init__(self):
self.__ultra_private = "我最深的秘密"

def reveal_secrets(self):
return self.__ultra_private

diary = SuperSecretDiary()
print(diary.reveal_secrets())  # 這會工作
# print(diary.__ultra_private)  # 這會引發 AttributeError
print(diary._SuperSecretDiary__ultra_private)  # 這會工作,但真的不推薦!

雙底線會導致 Python "重整"名稱,從而使外部更難以訪問(但不是不可能)。

使用屬性進行封裝

讓我們創建一個更複雜的例子 - 銀行帳戶:

class BankAccount:
def __init__(self, initial_balance=0):
self._balance = initial_balance

@property
def balance(self):
return self._balance

@balance.setter
def balance(self, value):
if value < 0:
raise ValueError("餘額不能為負")
self._balance = value

def deposit(self, amount):
if amount <= 0:
raise ValueError("存款金額必須為正")
self.balance += amount

def withdraw(self, amount):
if amount <= 0:
raise ValueError("提款金額必須為正")
if amount > self.balance:
raise ValueError("餘額不足")
self.balance -= amount

account = BankAccount(1000)
print(account.balance)  # 1000
account.deposit(500)
print(account.balance)  # 1500
account.withdraw(200)
print(account.balance)  # 1300
# account.balance = -500  # 這會引發 ValueError

這個BankAccount類別封裝了餘額,確保它不會變為負數,並且存款和提款都是有效的。

封裝方法表格

方法 描述 示例
底線前缀 指示私有屬性 self._private_var
屬性裝飾器 為屬性創建獲取器 @property
設定器裝飾器 為屬性創設設定器 @attribute.setter
名稱重整 創建強私有屬性 self.__very_private

結論

封裝就像是你數據的負責任守護者。這不是關於保密,而是關於確保你的數據被細心且有意識地處理。當你繼續你的 Python 之旅時,你會發現封裝是創建有韌性和可維護代碼的無價工具。

記住,年輕的 Pythonist,能力越大,責任越大。明智地使用封裝,你的代碼會感謝你的!

現在,勇敢地去封裝吧!並且不要忘記在你的(良好保護的)日記中寫下你學到的所有酷炫 Python 知識。編程愉快!

Credits: Image by storyset