property ----把函数的调用伪装成对属性的访问
class Movie:
def __init__(self,title,budget):
self.title = title
self.budget = budget
d1 = Movie('电影名称',30)
d1.budget = -100
print(d1.budget)
输出:
-100
你意识到:如果不小心给电影打了负分怎么办?你觉得这是错误的行为,希望Movie类可以阻止这个错误。
我们用@property装饰器指定了一个getter方法,用@budget.setter装饰器指定了一个setter方法。当我们这么做时,每当有人试着访问budget属性,Python就会自动调用相应的getter/setter方法。比方说,当遇到d1.budget = value这样的代码时就会自动调用budget.setter。
class Movie:
def __init__(self,title,budget):
self.title = title
self._budget = budget
@property
def budget(self):
return self._budget
@budget.setter
def budget(self,value):
if value < 0:
raise ValueError('输入值有误')
self._budget = value
d1 = Movie('电影名称',30)
d1.budget = -100
print(d1.budget)
输出:
ValueError: 输入值有误
property让我们将自定义的代码同变量的访问/设定联系在了一起,同时为你的类保持一个简单的访问属性的接口。
对property来说,最大的缺点就是它们不能重复使用。
当需要为输入的字段都添加检查时,可以看到代码增加了不少,但重复的逻辑也出现了不少。虽然property可以让类从外部看起来接口整洁漂亮,但是却做不到内部同样整洁漂亮。
描述符是property的升级版,允许你为重复的property逻辑编写单独的类来处理。即把实例属性交给描述符代理,进行判断检测等处理后执行.
类型检测案例:
class Typed:
def __init__(self,key,expected_type):
self.key = key
self.expected_type = expected_type
def __get__(self, instance, owner):
return instance.__dict__[self.key]
def __set__(self, instance, value):
if not isinstance(value,self.expected_type):
raise TypeError('%s传入的类型不是%s'%(value,self.expected_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print(instance.__dict__.pop(self.key))
class Movie:
title = Typed('title',str)
rating = Typed('rating',int)
runtime = Typed('runtime',int)
budget = Typed('budget',int)
gross = Typed('gross',int)
def __init__(self, title, rating, runtime, budget, gross):
self.title = title
self.rating = rating
self.runtime = runtime
self.budget = budget
self.gross = gross
d1 = Movie('电影名称','dg',24,535,6346)
print(d1.__dict__)
抛出错误:
dg传入的类型不是<class ‘int’>
描述符优先级(本质是底层字典的覆盖):
类属性>数据描述符>实例属性>非数据描述符>__ getattr __
同时具有__ get __ 属性和__ set __ 属性的新式类是数据描述符,
只具有__ get __ 属性的新式类是非数据描述符