初學者指南:深入了解 Python 中的 Getter 與 Setter

更新日期: 2024 年 10 月 12 日

在學習 Python 的物件導向程式設計(Object-Oriented Programming, OOP)時,屬性(Attributes) 的存取和控制是一個重要的課題。

為了保護物件的內部狀態,並提供對屬性值的驗證和控制,程式設計師常常使用 GetterSetter 方法。

在其他編程語言中,如 Java 或 C++,Getter 和 Setter 是以明確的方法形式存在的。

而在 Python 中,我們可以透過 @property 裝飾器,優雅地實現屬性的獲取和設置。

本文將為新手詳細介紹 Python 中的 Getter 與 Setter,解釋其作用、如何定義和使用,以及它們的重要性。


什麼是 Getter 與 Setter?

  • Getter 方法:用於獲取物件屬性的值。
  • Setter 方法:用於設置物件屬性的值,同時可以進行資料驗證或其他操作。

透過 Getter 和 Setter,我們可以對屬性的讀取和寫入進行控制,實現資料的封裝和保護。

為什麼需要 Getter 與 Setter?

  1. 資料封裝:保護物件的內部狀態,不被外部直接修改。
  2. 資料驗證:在設置屬性時,可以進行驗證,確保資料的有效性。
  3. 控制訪問:可以控制屬性的讀取和寫入行為,例如設置只讀屬性。

示例

假設我們有一個表示人的類別:

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

如果我們直接修改 age 屬性,可能會導致不合理的值:

person = Person("Alice", 30)
person.age = -5  # 年齡不可能為負數

透過 Getter 和 Setter,我們可以防止這種情況的發生。


基本實現方式

使用普通方法實現 Getter 和 Setter

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

    def get_age(self):
        return self._age

    def set_age(self, age):
        if age >= 0:
            self._age = age
        else:
            raise ValueError("年齡不能為負數")
  • 說明
  • 我們使用 _age 作為實際存儲年齡的變數,前面的下劃線表示這是一個受保護的屬性。
  • get_age 方法用於獲取 _age 的值。
  • set_age 方法在設置 _age 時進行了驗證。

使用 Getter 和 Setter

person = Person("Alice", 30)
print(person.get_age())  # 輸出:30

person.set_age(35)
print(person.get_age())  # 輸出:35

person.set_age(-5)  # 引發 ValueError:年齡不能為負數

使用 @property 裝飾器

Python 提供了 @property 裝飾器,讓我們可以使用屬性存取的方式來調用 Getter 和 Setter,使代碼更加優雅。

定義屬性

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age  # 這裡會調用下面的 @age.setter

    @property
    def age(self):
        return self._age  # 這裡的 _age 是實際存儲的變數

    @age.setter
    def age(self, value):
        if value >= 0:
            self._age = value
        else:
            raise ValueError("年齡不能為負數")
  • 說明
  • @property 裝飾器將一個方法轉換為屬性訪問,這樣我們可以使用 person.age 的方式,而不是 person.get_age()
  • @age.setter 定義了對應屬性的設置方法。

使用屬性

person = Person("Alice", 30)
print(person.age)  # 輸出:30

person.age = 35
print(person.age)  # 輸出:35

person.age = -5  # 引發 ValueError:年齡不能為負數
  • 優點:使用屬性方式訪問,更加直觀,符合 Python 的風格。

完整示例

定義一個矩形類別,帶有長度和寬度屬性,並計算面積

class Rectangle:
    def __init__(self, width, height):
        self.width = width   # 調用 @width.setter
        self.height = height # 調用 @height.setter

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, value):
        if value > 0:
            self._width = value
        else:
            raise ValueError("寬度必須為正數")

    @property
    def height(self):
        return self._height

    @height.setter
    def height(self, value):
        if value > 0:
            self._height = value
        else:
            raise ValueError("高度必須為正數")

    @property
    def area(self):
        return self.width * self.height  # 這裡調用的是屬性方法

    @property
    def perimeter(self):
        return 2 * (self.width + self.height)

使用類別

rect = Rectangle(5, 3)
print(f"寬度:{rect.width}")       # 輸出:寬度:5
print(f"高度:{rect.height}")      # 輸出:高度:3
print(f"面積:{rect.area}")        # 輸出:面積:15
print(f"周長:{rect.perimeter}")   # 輸出:周長:16

rect.width = 10
print(f"新的面積:{rect.area}")    # 輸出:新的面積:30

rect.height = -5  # 引發 ValueError:高度必須為正數
  • 說明
  • areaperimeter 定義為只讀屬性,沒有對應的 setter 方法。
  • 在設置 widthheight 時,進行了值的驗證。

注意事項

  1. 命名規範:實際存儲變數通常以單下劃線開頭,例如 _age_width,表示受保護的屬性,不應直接訪問。
  2. 只讀屬性:如果只定義 @property,未定義對應的 setter,則該屬性為只讀。
   class Person:
       @property
       def name(self):
           return self._name
  1. 刪除屬性:可以使用 @屬性名.deleter 來定義屬性的刪除行為。
   class Person:
       @property
       def age(self):
           return self._age

       @age.deleter
       def age(self):
           del self._age
  1. 性能考量:過度使用屬性可能會影響性能,應根據實際情況選擇。

結論

透過使用 Python 的 @property 裝飾器,我們可以優雅地實現 Getter 和 Setter,對屬性的訪問進行控制,同時保持代碼的簡潔和可讀性。這有助於:

  • 保護資料完整性:防止不合理的值被設置。
  • 提高代碼可讀性:使用屬性訪問方式,更加直觀。
  • 實現封裝性:隱藏內部實現細節,對外提供統一的介面。

希望通過本文的介紹,您對 Python 中的 Getter 與 Setter 有了更深入的了解,並能在實際開發中靈活運用。


進一步學習

  • 深入理解 @property 裝飾器:瞭解其工作原理和更多應用。
  • 學習其他特殊方法:如 __getattr____setattr__,實現更高級的屬性控制。
  • 設計模式:學習如何在設計模式中應用 Getter 和 Setter,如單例模式、觀察者模式等。
  • 資料封裝與繼承:結合繼承,實現更複雜的物件導向設計。

Similar Posts