自定义属性访问

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__()

# 类定义的其余部分见上

  def __getattr__(self, name):
    # 在此实现逻辑
    ...

对象的命名空间是与该对象关联的属性集合

__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__() 设置的属性
  • 接收属性名 name 和值 value
  • 利用对象的 __dict__ 属性

$$

$$

用于控制属性变更、校验和转换

# 类定义的其余部分见上

  def __setattr__(self, name, value):
    # 在此实现逻辑
    ...

    # 使用 __dict__ 创建/更新属性
    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__ 实战

# 使用 str 类型的值设置属性
karina.residence_hall = "Honors College South"
print(karina.residence_hall)
Setting residence_hall = Honors College South
Honors College South
# 使用 int 类型的值设置属性
karina.student_id = 19301872
...
    raise Exception("Unexpected data type!")
Exception: Unexpected data type!
Python 面向对象编程进阶

结合使用 __getattr__ 与 __setattr__

class Student:
    ...   

    def __getattr__(self, name):
        # 使用占位符设置属性
        self.__setattr__(name, None)
        return None

    def __setattr__(self, name, value):
        if value is None:  # 打印占位符提示
            print(f"Setting placeholder for {name}")

        self.__dict__[name] = value  # 设置属性
Python 面向对象编程进阶

Passons à la pratique !

Python 面向对象编程进阶

Preparing Video For Download...