# 如果需要自定义对属性的访问,最好的办法就是将属性定义为一个property # 在这个类中,我们将first_name的getter方法作为一个property # 在初始化调用时,其实调用了setter方法,跳过了first_name直接访问了_first_name class Person: def __init__(self, first_name): self.first_name = first_name @property def first_name(self): return self._first_name @first_name.setter def first_name(self, first_name): if not isinstance(first_name, str): raise TypeError('First name must be str') self._first_name = first_name @first_name.deleter def first_name(self): raise AttributeError('First name cannot be deleted') # property的重要特性就是根据访问的不同形式,自动触发getter setter deleter p = Person("Susan") print(p.first_name) p.first_name = "blyet" print(p.first_name) # del p.first_name # 对于已经存在的get和set方法,也可以使用property变成内置形式 class Person2: def __init__(self, first_name): self.set_first_name(first_name) def get_first_name(self): return self._first_name def set_first_name(self, first_name): if not isinstance(first_name, str): raise TypeError('First name must be str') self._first_name = first_name def delete_first_name(self): raise AttributeError('First name cannot be deleted') name = property(get_first_name, set_first_name, delete_first_name) p = Person2("Susan") print(p.name) p.name = "blyet" print(p.name) # del p.name # 这种方法一般用于确定要在访问属性的时候对它进行一些额外操作的时候,其他场景下尽量不要这么做,这会让程序变慢 # property也可以用来做一些类似懒加载的实时计算属性 import math class Circle: def __init__(self, radius): self.radius = radius @property def area(self): return math.pi * self.radius ** 2 @property def perimeter(self): return 2 * self.radius c = Circle(5) print(c.radius) print(c.area) print(c.perimeter) # 虽然这样确实很优雅,但是在Python被大型程序集成的时候,还是使用传统getter和setter好 # 另外,不要在类里写大量的property!!!!,这会让代码膨胀且可读性变差,会变得难以维护,像下面这样 class Person3: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name @property def first_name(self): return self._first_name @first_name.setter def first_name(self, first_name): if not isinstance(first_name, str): raise TypeError('First name must be str') self._first_name = first_name # 不要这样重复写property! @property def last_name(self): return self._last_name @last_name.setter def last_name(self, last_name): if not isinstance(last_name, str): raise TypeError('Last name must be str') self._last_name = last_name