1. 作用
描述器的本质是一个对象,当对此对象进行增删改查操作时,会受到描述器的限制,比如更改的值不能为负等。
2. 描述器的创建
2.1 方式一
class Person:
def __init__(self):
self.__age = 10
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
if value < 0:
value = 0
self.__age = value
@age.deleter
def age(self):
print("del age")
del self.__age
# 第二种 property 的使用方式
# age = property(get_age, set_age, del_age)
name = "sz"
p = Person()
p.age = 19
print(p.age)
p.age = -19
print(p.age)
del p.age
print(p.age)
执行结果:
上述方法的缺陷: 1
个属性就需要定义 3
个方法来控制,那 3
个属性就需要 9
个方法,很繁琐!
2.2 方式二
在一个新的类中实现 __get__
、__set__
、__delete__
方法
class Age:
# self 表示创建的实例, instance 表示目前的属性
def __get__(self, instance, owner):
print("get")
# value 表示目前设置的值
def __set__(self, instance, value):
print("set")
def __delete__(self, instance):
print("delete")
class Person:
age = Age()
p = Person()
p.age = 10
print(p.age)
del p.age
执行结果:
注:在经典类中执行 p.age = 10
,并不会调用 Age
中的三个方法,而是创建了一个实例属性
2.2.1 使用类进行调用
class Age(object):
def __get__(self, instance, owner):
print("get")
def __set__(self, instance, value):
print("set")
def __delete__(self, instance):
print("delete")
class Person(object):
age = Age()
print(Person.age)
Person.age = 19
del Person.age
执行结果: 利用类进行调用时,只调用了 __get__
方法,并没有调用 __set__
和 __delete__
方法
2.3 资料描述器与非资料描述器
- 描述器中实现了
get
、set
方法 - 描述器中只实现了
get
方法 - 优先级: 资料描述器 > 实例属性 > 非资料描述器
资料描述器的优先级
class Age(object):
def __get__(self, instance, owner):
print("get")
def __set__(self, instance, value):
print("set")
def __delete__(self, instance):
print("delete")
class Person(object):
age = Age()
def __init__(self):
self.age = 10
p = Person()
p.age = 10
print(p.age)
# del p.age
print(p.__dict__)
执行结果:
非资料描述器的优先级
class Age(object):
def __get__(self, instance, owner):
print("get")
class Person(object):
age = Age()
def __init__(self):
self.age = 10
p = Person()
p.age = 10
print(p.age)
# del p.age
print(p.__dict__)
执行结果:
2.4 值的存储问题
class Age(object):
def __get__(self, instance, owner):
print("get")
def __set__(self, instance, value):
print("set", self, instance, value)
def __delete__(self, instance):
print("delete")
class Person(object):
age = Age()
p1 = Person()
p1.age = 10
p2 = Person()
p2.age = 11
执行结果: 但是可以看出打印的 instance
是不同的地址
图解:
解决值存储问题: 将属性绑定到 instance
上
class Age(object):
def __get__(self, instance, owner):
print("get")
return instance.v
def __set__(self, instance, value):
print("set", self, instance, value)
instance.v = value
def __delete__(self, instance):
print("delete")
del instance.v
class Person(object):
age = Age()
p1 = Person()
p1.age = 10
print(p1.age)
# # del p.age
#
p2 = Person()
p2.age = 11
print(p2.age)
print(p1.age)
执行结果: