自訂屬性存取

Python 物件導向程式設計進階

Jake Roach

Data Engineer

AttributeError

class Student:
  def __init__(self, student_name, major):
    self.student_name = student_name
    self.major = major
...
karina = Student("Karina", "Literature")
student.residence_hall  # 嘗試存取不存在的屬性
...
AttributeError: 'Student' object has no attribute 'residence_hall'
Python 物件導向程式設計進階

__getattr__()

# Rest of the class definition above

  def __getattr__(self, name):
    # Implement logic here
    ...

物件的命名空間是與該物件關聯的一組屬性

當嘗試參照「物件命名空間外」的任何屬性時,會執行 __getattr__()

  • 魔術方法,不會被直接呼叫
  • 接受 name 參數
  • 可自訂行為,而非拋出 AttributeError
Python 物件導向程式設計進階

解決 AttributeError

class Student:
  def __init__(self, student_name, major):
    self.student_name = student_name
    self.major = major

  def __getattr__(self, name):
      print(f"""{name} does not exist in this object's namespace, try setting 
            a value for {name} first""")
karina.residence_hall  # 現在再嘗試讀取 residence_hall 屬性
residence_hall does not exist in this object's namespace, try setting a value for 
  residence_hall first
Python 物件導向程式設計進階

__setattr__()

__setattr__() 是在設定或更新(新屬性或既有屬性)時會執行的魔術方法。

  • 包含用 __init__() 設定的屬性
  • 接受屬性的 namevalue
  • 利用物件的 __dict__ 屬性

$$

$$

用於控管屬性變更、驗證、轉換

# Rest of the class definition above

  def __setattr__(self, name, value):
    # Implement logic here
    ...

    # Use __dict__ to create/update 
    # the attribute
    self.__dict__[name] = value

__dict__ 會儲存物件的所有屬性,可用來讀寫資料

Python 物件導向程式設計進階

自訂屬性儲存

class Student:
  def __init__(self, student_name, major):
    self.student_name = student_name
    self.major = major

  def __setattr__(self, name, value):
    # If value is a string, set the attribute using the __dict__ attribute
    if isinstance(value, str):
      print(f"Setting {name} = {value}")
      self.__dict__[name] = value

    else: # Otherwise, raise an exception noting an incorrect data type
        raise Exception("Unexpected data type!")
Python 物件導向程式設計進階

__setattr__ 的實作

# 以字串值設定屬性
karina.residence_hall = "Honors College South"
print(karina.residence_hall)
Setting residence_hall = Honors College South
Honors College South
# 以整數值設定屬性
karina.student_id = 19301872
...
    raise Exception("Unexpected data type!")
Exception: Unexpected data type!
Python 物件導向程式設計進階

同時使用 __getattr__ 與 __setattr__

class Student:
    ...   

    def __getattr__(self, name):
        # Set the attribute with a placeholder
        self.__setattr__(name, None)
        return None

    def __setattr__(self, name, value):
        if value is None:  # Print a message denoting a placeholder
            print(f"Setting placeholder for {name}")

        self.__dict__[name] = value  # Set the attribute
Python 物件導向程式設計進階

一起來練習吧!

Python 物件導向程式設計進階

Preparing Video For Download...