Python3基础-自定制property
一、类函数没有加@的执行结果
class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height def type(self): return self.name
以上代码执行结果就为空,
二、若是在类函数type上一行加上@testproperty 则:
class testproperty: def __init__(self,func): self.func = func print('func===',func) class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name
@testproperty 相当于type=testproperty(type) 就相当于在类People 添加一个类属性;就是在实例化testproperty(type)
则运行结果如下
func=== <function People.type at 0x039CF780>
上面的代码再加上
p1 = People('SUSU',90,'1米65') print(p1.type)
则p1.type输出的结果是<__main__.testproperty object at 0x010901F0> 因为@testproperty 相当于type=testproperty(type) ;则type就是一个实例化对象
要输出type()函数的返回值,则 p1.type.func(p1)
print(p1.type.func(p1)) #输出的是SUSU
三、利用描述符自定制
#实例调用 class testproperty: def __init__(self,func): self.func = func #print('func===',func) def __get__(self, instance, owner): print(self) #<__main__.testproperty object at 0x01155670> print(instance) #<__main__.People object at 0x01155710> 即是p1 print(owner) #<class '__main__.People'> val = self.func(instance) return val class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name p1 = People('SUSU',90,'1米65') #实例调用 print(p1.type) #输出的是SUSU
#类的调用 class testproperty: def __init__(self,func): self.func = func #print('func===',func) def __get__(self, instance, owner): print(self) #<__main__.testproperty object at 0x01155670> print(instance) #None print(owner) #<class '__main__.People'> val = self.func(instance) #报错 AttributeError: 'NoneType' object has no attribute 'name' return val class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name p1 = People('SUSU',90,'1米65') #类调用 print(People.type)
类的调用 People.type, 传入get函数是 instance的值为空,则在val=self.func(instance) 则会出现报错AttributeError: 'NoneType' object has no attribute 'name'
默认property的实例调用和类调用出现的情况:
class testproperty: def __init__(self,func): self.func = func #print('func===',func) def __get__(self, instance, owner): print(self) #<__main__.testproperty object at 0x01155670> print(instance) #None print(owner) #<class '__main__.People'> val = self.func(instance) #报错 AttributeError: 'NoneType' object has no attribute 'name' return val #默认@property class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name @property #eat = property(eat) 默认的 def eat(self): return self.age p1 = People('SUSU',90,'1米65') # 实例调用 # print(p1.type) #类调用 # print(People.type) print(p1.eat) #@property 实例调用则输出 90 print(People.eat) #@property 类调用则输出 <property object at 0x02DB8450>
则自定制的testproperty;可以修改如下
class testproperty: def __init__(self,func): self.func = func #print('func===',func) def __get__(self, instance, owner): if instance is None: #新增判断如果是类调用,则返回self return self val = self.func(instance) return val class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name @property #eat = property(eat) 默认的 def eat(self): return self.age p1 = People('SUSU',90,'1米65') print(p1.type) #@testproperty 实例调用则输出SUSU print(People.type) #@testproperty 类的调用则输出<__main__.testproperty object at 0x02F25710>
四、自定制property实现延迟计算功能
class testproperty: def __init__(self,func): self.func = func def __get__(self, instance, owner): print('get方法') if instance is None: return self val = self.func(instance) setattr(instance,self.func.__name__,val) #则将val 放置到p1字典里面,key的值为type #取一个函数的函数名称为 type.__name__ 则在该类里面type为 self.func return val class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name @property #eat = property(eat) 默认的 def eat(self): return self.age p1 = People('SUSU',90,'1米65') print(p1.__dict__) print(p1.type) print(p1.__dict__) print(p1.type) print(p1.type)
执行结果如下:
{'name': 'SUSU', 'age': 90, 'height': '1米65'} get方法 SUSU {'name': 'SUSU', 'age': 90, 'height': '1米65'} get方法 SUSU get方法 SUSU
由此可以看出以上代码p1.type执行了三次,则get方法也执行了三次
优化一下,get无需一直执行
class testproperty: def __init__(self,func): self.func = func def __get__(self, instance, owner): print('get方法') if instance is None: return self val = self.func(instance) setattr(instance,self.func.__name__,val) #则将val 放置到p1字典里面,key的值为type #取一个函数的函数名称为 type.__name__ 则在该类里面type为 self.func return val class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name p1 = People('SUSU',90,'1米65') print(p1.__dict__) print(p1.type) print(p1.__dict__) print(p1.type) print(p1.type)
以上执行的结果
{'name': 'SUSU', 'age': 90, 'height': '1米65'} get方法 SUSU {'name': 'SUSU', 'age': 90, 'height': '1米65', 'type': 'SUSU'} SUSU #因为p1字典里面有了type;则直接从实例字典里面读取 SUSU
第一次运行时,实例属性字典没有该属性type,则运行非数据描述符,运行之后setattr(instance,self.func.__name__,val) #则将val 放置到实例属性字典里面,key的值为type
第二次运行时,因为实例属性优先级高于非数据描述符,则会先在实例属性字典里面找。{'name': 'SUSU', 'age': 90, 'height': '1米65', 'type': 'SUSU'};则就直接取该属性的值,就无需运行描述符类
如果描述符类加上set函数,则运行结果
class testproperty: def __init__(self,func): self.func = func def __get__(self, instance, owner): print('get方法') if instance is None: return self val = self.func(instance) setattr(instance,self.func.__name__,val) #则将val 放置到p1字典里面,key的值为type #取一个函数的函数名称为 type.__name__ 则在该类里面type为 self.func return val def __set__(self, instance, value): pass class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @testproperty #type=testproperty(type) 就相当于在类People 添加一个类属性 def type(self): return self.name p1 = People('SUSU',90,'1米65') print(p1.__dict__) print(p1.type) print(p1.__dict__) print(p1.type) print(p1.type)
以上代码执行结果如下:
{'name': 'SUSU', 'age': 90, 'height': '1米65'} get方法 SUSU {'name': 'SUSU', 'age': 90, 'height': '1米65'} get方法 SUSU get方法 SUSU
是因为实例属性优先级低于数据描述符;每次运行查找数据描述符
五、
property 的 getter,setter 和 deleter 方法同样可以用作装饰器
class People: def __init__(self,name,age,height): self.name = name self.age = age self.height = height @property #read() 方法转化成同名只读属性的 getter 方法 def read(self): print(self.name) return self.name @read.setter def read(self,val): self.name = val print(self.name) return self.name @read.deleter def read(self): print('删除') del self.name #只有在属性read定义property 后才能定义read.setter,read.deleter p1 = People('susu',18,'hahh') print(p1.__dict__) p1.read p1.read = 'xioa' del p1.read print(p1.__dict__)
以上代码执行结果如下:
{'name': 'susu', 'age': 18, 'height': 'hahh'} susu xioa 删除 {'age': 18, 'height': 'hahh'}
另外一种方法使用
property() 函数的作用是在新式类中返回属性值。
class property([fget[, fset[, fdel[, doc]]]])
- fget -- 获取属性值的函数
- fset -- 设置属性值的函数
- fdel -- 删除属性值函数
- doc -- 属性描述信息
class People: def __init__(self,name,age,height): self._name = name self.age = age self.height = height def get_name(self): print(self._name) return self._name def set_name(self,val): self._name = val print(self._name) return self._name def del_name(self): print('删除') del self._name name = property(get_name,set_name,del_name,"I'm the 'x' property.") p1 = People('susu',18,'hahh') print(p1.__dict__) p1.name p1.name= 'xioa' del p1.name print(p1.__dict__) """ 以上代码执行结果如下 {'_name': 'susu', 'age': 18, 'height': 'hahh'} susu xioa 删除 {'age': 18, 'height': 'hahh'} """