描述符及类的装饰器应用实现类型检查,自定制property,property补充,property实现类型检查
2021/5/12 18:29:40
本文主要是介绍描述符及类的装饰器应用实现类型检查,自定制property,property补充,property实现类型检查,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
'''描述符及类的装饰器应用''' # class Typed: # '''这是一个数据描述符''' # def __init__(self, one, two): # self.one = one # self.two = two # # def __set__(self, instance, value): # 此步操作是People类实例化时或者单独给类设置值时才会触发 # if type(value) == self.two: # instance.__dict__[self.one] = value # else: # raise TypeError('输入类型错误!') # # def __get__(self, instance, owner): # ③然后执行的是__get__方法 # # return instance.__dict__[self.one] # print('***') # # def __delete__(self, instance): # instance.__dict__.pop(self.one) # # # def deco(**kwargs): # '''这是一个装饰器''' # def wrapper(func): # for key,val in kwargs.items(): # setattr(func, key, Typed(key, val)) # 设置类属性 # return func # return wrapper # # # @deco(name=str, age=int, salary=float, gender=str, height=int) # class People: # '''这是一个类,实现了自由定制类属性及实例化参数类型限制''' # # name = Typed('name', str) # ②所以访问的是这一步 # # age = Typed('age', int) # # salary = Typed('salary', float) # # gender = Typed('gender', str) # # height = Typed('height', int) # def __init__(self, name, age, salary, gender, height): # self.name = name # self.age = age # self.salary = salary # self.gender = gender # self.height = height # p1 = People('alex', 18, 1000.55, 'x', 170) # p1.name # ①数据描述符大于实例属性 # print(People.__dict__) '''自定制property''' # class Lazyproperty: # def __init__(self, func): # # print(func) # <function Room.area at 0x000001C226872EE0> # self.func = func # # def __get__(self, instance, owner): # if instance is None: # return self # 当类调用时,返回实例本身(即一个内存地址) # return self.func(instance) # # class Room: # def __init__(self, name, width, length): # self.name = name # self.width = width # self.length = length # # @Lazyproperty # area = Lazyproperty(area),由类来作为装饰器,此步操作相当于实例化过程;相当于是给类设置类属性,所以可以让Lazyproperty写成描述符 # # @property # area = property(area) # def area(self): # 由property装饰器装饰时:'area': <property object at 0x000001940DF045E0> # return self.width * self.length # # def func(self): # 'func': <function Room.func at 0x000001940DF02E50> # return '...' # r1 = Room('客厅', 6, 7) # print(r1.area.func(r1)) # 没有__get__方法时,r1为Room实例,area由装饰器修饰后为Lazyproperty实例,所以有func,加上括号运行,参数为实例本身即r1 # print(Room.__dict__) # print(r1.area) '''自我总结:这个装饰器不再是函数,而是一个类,且这个类属于描述符;在@的时候这一步相当于实例化,也等同于描述符设置类属性的过程;此时描述符有个__get__方法, instance是Room类的实例r1,owner是Room类,而self.func指向的是Room类的area属性地址,加括号即可运行;所以__get__方法等同于运行了Room类 的area方法,而r1.area因为描述符的原因会去找Lazyproperty中的__get__方法''' # 当实例调用时,__get__方法的instance为实例本身;当类调用时,instance为None,所以自己这样的定制的装饰器会报错,而python提供的property # 则返回一个对象内存地址,那么加上一个if判断即可;此时类调用也就不会报错了 # print(Room.area) '''自定制property实现延迟计算功能''' # class Lazyproperty1: # def __init__(self, func): # self.func = func # # def __get__(self, instance, owner): # # print(self) # <__main__.Lazyproperty1 object at 0x000001C6EE413D30> # print('get') # if instance is None: # return self # setattr(instance, self.func.__name__, self.func(instance)) # 设置实例字典属性,因为是非数据描述符,所以优先级的问题,实例属性有的,就不会去非数据描述符去找 # return self.func(instance) # # class Room1: # def __init__(self, name, width, length): # self.name = name # self.width = width # self.length = length # # @Lazyproperty1 # def area(self): # return int(self.width * self.length) # # @property # def area1(self): # return int(self.width / self.length) # # r2 = Room1('卧室', 10, 10) # print(r2.area1) # print(r2.area) # 此时第一次运行会打印get # print(r2.__dict__) # {'name': '卧室', 'width': 10, 'length': 10, 'area': 100} # print(r2.area) # 第二次及往后的运行,就不会再打印get了,因为实例字典属性能找到,这样就不需要每次都运行函数进行计算了;如果描述符加了__set__成了数据描述符,结果又不一样了,因为优先级改变了 '''property补充''' # class Foo: # @property # def ABC(self): # print('get时候运行') # # @ABC.setter # def ABC(self, value): # print('set时候运行', value) # # @ABC.deleter # def ABC(self): # print('delete时候运行') # 只有在属性ABC定义property后才能定义ABC.setter和ABC.deleter # foo = Foo() # foo.ABC # foo.ABC = 'nnn' # 此时没有任何定义,报错AttributeError: can't set attribute # foo.ABC = 'mmm' # del foo.ABC # 另一种写法 # class Foo1: # def get_aaa(self): # print('get') # # def set_aaa(self, value): # print('set') # # def del_aaa(self): # print('del') # # aaa = property(get_aaa, set_aaa, del_aaa) # 括号里顺序不能变,必须是get,set,del # # f1 = Foo1() # f1.aaa # f1.aaa = 'bcbc' # del f1.aaa '''property应用''' # class Goods: # def __init__(self): # self.original_price = 100 # 原价 # self.discount = 0.8 # 折扣 # # @property # def price(self): # new_price = self.original_price * self.discount # 打完折扣后的加个 # return new_price # # @price.setter # def price(self, value): # 只能传入一个参数? # self.original_price = value # 修改后的价格 # # @price.deleter # def price(self): # del self.original_price # # g1 = Goods() # print(g1.price) # 获取商品打完折扣后的价格80.0 # g1.price = 200 # print(g1.price) # 修改商品价格后的价格160.0 # del g1.price # print(g1.price) # AttributeError: 'Goods' object has no attribute 'original_price' # property实现类型检查 # class Typed: # def __init__(self, name): # self.name = name # 实例化就触发property # # @property # def name(self): # # return self.name # 如果只写一个property,property自动实现了set和get方法属于数据描述符,比实例属性优先级高,所以会触发property内置的set,抛出异常 # return self.doubi # # @name.setter # def name(self, value): # if not isinstance(value, str): # 必须是字符串类型 # raise TypeError('输入类型错误') # self.doubi = value # # @name.deleter # def name(self): # del self.doubi # # t1 = Typed('alex') # t2 = Typed(111)
这篇关于描述符及类的装饰器应用实现类型检查,自定制property,property补充,property实现类型检查的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-22项目:远程温湿度检测系统
- 2024-12-21《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》简介
- 2024-12-21后台管理系统开发教程:新手入门全指南
- 2024-12-21后台开发教程:新手入门及实战指南
- 2024-12-21后台综合解决方案教程:新手入门指南
- 2024-12-21接口模块封装教程:新手必备指南
- 2024-12-21请求动作封装教程:新手必看指南
- 2024-12-21RBAC的权限教程:从入门到实践
- 2024-12-21登录鉴权实战:新手入门教程
- 2024-12-21动态权限实战入门指南