Python之描述符的功能实例
感兴趣的小伙伴,下面一起跟随php教程的雯雯来看看吧!
一、描述符定义
描述符
这篇文章主要为大家详细介绍了Python之描述符的功能实例,具有一定的参考价值,可以用来参考一下。
感兴趣的小伙伴,下面一起跟随php教程的雯雯来看看吧!
一、描述符定义
描述符是一种类,我们把实现了__get__()、__set__()和__delete__()中的其中任意一种方法的类称之为描述符。
描述符的作用是用来代理一个类的属性,需要注意的是描述符不能定义在被使用类的构造函数中,只能定义为类的属性,它只属于类的,不属于实例,我们可以通过查看实例和类的字典来确认这一点。
描述符是实现大部分Python类特性中最底层的数据结构的实现手段,我们常使用的@classmethod、@staticmethd、@property、甚至是__slots__等属性都是通过描述符来实现的。它是很多高级库和框架的重要工具之一,是使用到装饰器或者元类的大型框架中的一个非常重要组件。
如下示例一个描述符及引用描述符类的代码:
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <code> class Descriptors: def __init__(self, key, value_type): self.key = key self.value_type = value_type def __get__(self, instance, owner): print ( "===> 执行Descriptors的 get" ) return instance.__dict__[self.key] def __set__(self, instance, value): print ( "===> 执行Descriptors的 set" ) if not isinstance(value, self.value_type): raise TypeError( "参数%s必须为%s" % (self.key, self.value_type)) instance.__dict__[self.key] = value def __delete__(self, instance): print ( "===> 执行Descriptors的delete" ) instance.__dict__.pop(self.key) class Person: name = Descriptors( "name" , str) age = Descriptors( "age" , int) def __init__(self, name, age): self.name = name self.age = age person = Person( "xu" , 15) print (person.__dict__) person.name person.name = "xu-1" print (person.__dict__) # 结果: # ===> 执行Descriptors的 set # ===> 执行Descriptors的 set # { 'name' : 'xu' , 'age' : 15} # ===> 执行Descriptors的 get # ===> 执行Descriptors的 set # { 'name' : 'xu-1' , 'age' : 15} </code> |
Python基础分析之描述符
其中,Descriptors类就是一个描述符,Person是使用描述符的类。
类的__dict__属性是类的一个内置属性,类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里。
在输出描述符的变量时,会调用描述符中的__get__方法,在设置描述符变量时,会调用描述符中的__set__方法。
二、描述符的种类和优先级
描述符分为数据描述符和非数据描述符。
至少实现了内置__set__()和__get__()方法的描述符称为数据描述符;实现了除__set__()以外的方法的描述符称为非数据描述符。
描述符的优先级的高低顺序:类属性 > 数据描述符 > 实例属性 > 非数据描述符 > 找不到的属性触发__getattr__()。
在上述“描述符定义”章节的例子中,实例person的属性优先级低于数据描述符Descriptors,所以在赋值或获取值过程中,均调用了描述符的方法。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <code> class Descriptors: def __get__(self, instance, owner): print ( "===> 执行 Descriptors get" ) def __set__(self, instance, value): print ( "===> 执行 Descriptors set" ) def __delete__(self, instance): print ( "===> 执行 Descriptors delete" ) class University: name = Descriptors() def __init__(self, name): self.name = name </code> |
Python基础分析之描述符
类属性 > 数据描述符
代码如下:
1 2 3 4 5 6 7 8 | <code> # 类属性 > 数据描述符 # 在调用类属性时,原来字典中的数据描述法被覆盖为 XX-XX print (University.__dict__) # {..., 'name' : <__main__.Descriptors object at 0x7ff8c0eda278>,} University.name = "XX-XX" print (University.__dict__) # {..., 'name' : 'XX-XX' ,} </code> |
Python基础分析之描述符
数据描述符 > 实例属性
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 | <code> # 数据描述符 > 实例属性 # 调用时会现在实例里面找,找不到name属性,到类里面找,在类的字典里面找到 'name' : <__main__.Descriptors object at 0x7fce16180a58> # 初始化时调用 Descriptors 的 __set__; un.name 调用 __get__ print (University.__dict__) un = University( "xx-xx" ) un.name # 结果: # {..., 'name' : <__main__.Descriptors object at 0x7ff8c0eda278>,} # ===> 执行 Descriptors set # ===> 执行 Descriptors get </code> |
Python基础分析之描述符
下面是测试 实例属性、 非数据描述符、__getattr__ 使用代码
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <code> class Descriptors: def __get__(self, instance, owner): print ( "===>2 执行 Descriptors get" ) class University: name = Descriptors() def __init__(self, name): self.name = name def __getattr__(self, item): print ( "---> 查找 item = {}" .format(item)) </code> |
Python基础分析之描述符
实例属性 > 非数据描述符
代码如下:
1 2 3 4 5 6 7 8 9 | <code> # 实例属性 > 非数据描述符 # 在创建实例的时候,会在属性字典中添加 name,后面调用 un2.name 访问,都是访问实例字典中的 name un2 = University( "xu2" ) print (un2.name) # xu 并没有调用到 Descriptors 的 __get__ print (un2.__dict__) # { 'name' : 'xu2' } un2.name = "xu-2" print (un2.__dict__) # { 'name' : 'xu-2' } </code> |
Python基础分析之描述符
非数据描述符 > 找不到的属性触发__getattr__
代码如下:
1 2 3 4 5 | <code> # 非数据描述符 > 找不到的属性触发__getattr__ # 找不到 name1 使用 __getattr__ un3 = University( "xu3" ) print (un3.name1) # ---> 查找 item = name1</code> |
Python基础分析之描述符
三、描述符的应用
使用描述符检验数据类型
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <code> class Typed: def __init__(self, key, type): self.key = key self.type = type def __get__(self, instance, owner): print ( "---> get 方法" ) # print ( "instance = {}, owner = {}" .format(instance, owner)) return instance.__dict__[self.key] def __set__(self, instance, value): print ( "---> set 方法" ) # print ( "instance = {}, value = {}" .format(instance, value)) if not isinstance(value, self.type): # print ( "设置name的值不是字符串: type = {}" .format(type(value))) # return raise TypeError( "设置{}的值不是{},当前传入数据的类型是{}" .format(self.key, self.type, type(value))) instance.__dict__[self.key] = value def __delete__(self, instance): print ( "---> delete 方法" ) # print ( "instance = {}" .format(instance)) instance.__dict__.pop(self.key) class Person: name = Typed( "name" , str) age = Typed( "age" , int) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary p1 = Person( "xu" , 99, 100.0) print (p1.__dict__) p1.name = "XU1" print (p1.__dict__) del p1.name print (p1.__dict__) # 结果: # ---> set 方法 # ---> set 方法 # { 'name' : 'xu' , 'age' : 99, 'salary' : 100.0} # ---> set 方法 # { 'name' : 'XU1' , 'age' : 99, 'salary' : 100.0} # ---> delete 方法 # { 'age' : 99, 'salary' : 100.0} </code> |
Python基础分析之描述符
四、描述符 + 类装饰器 (给 Person类添加类属性)
类装饰器,道理和函数装饰器一样
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <code> def Typed(**kwargs): def deco(obj): for k, v in kwargs.items(): setattr(obj, k, v) return obj return deco @Typed(x=1, y=2) # 1、Typed(x=1, y=2) ==> deco 2、@deco ==> Foo = deco(Foo) class Foo: pass # 通过类装饰器给类添加属性 print (Foo.__dict__) # {......, 'x' : 1, 'y' : 2} print (Foo.x) </code> |
Python基础分析之描述符
使用描述符和类装饰器给 Person类添加类属性
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | <code> "" " 描述符 + 类装饰器 "" " class Typed: def __init__(self, key, type): self.key = key self.type = type def __get__(self, instance, owner): print ( "---> get 方法" ) # print ( "instance = {}, owner = {}" .format(instance, owner)) return instance.__dict__[self.key] def __set__(self, instance, value): print ( "---> set 方法" ) # print ( "instance = {}, value = {}" .format(instance, value)) if not isinstance(value, self.type): # print ( "设置name的值不是字符串: type = {}" .format(type(value))) # return raise TypeError( "设置{}的值不是{},当前传入数据的类型是{}" .format(self.key, self.type, type(value))) instance.__dict__[self.key] = value def __delete__(self, instance): print ( "---> delete 方法" ) # print ( "instance = {}" .format(instance)) instance.__dict__.pop(self.key) def deco(**kwargs): def wrapper(obj): for k, v in kwargs.items(): setattr(obj, k, Typed(k, v)) return obj return wrapper @deco(name=str, age=int) class Person: # name = Typed( "name" , str) # age = Typed( "age" , int) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary p1 = Person( "xu" , 99, 100.0) print (Person.__dict__) print (p1.__dict__) p1.name = "XU1" print (p1.__dict__) del p1.name print (p1.__dict__) # 结果: # ---> set 方法 # ---> set 方法 # {..., 'name' : <__main__.Typed object at 0x7f3d79729dd8>, 'age' : <__main__.Typed object at 0x7f3d79729e48>} # { 'name' : 'xu' , 'age' : 99, 'salary' : 100.0} # ---> set 方法 # { 'name' : 'XU1' , 'age' : 99, 'salary' : 100.0} # ---> delete 方法 # { 'age' : 99, 'salary' : 100.0} </code> |
Python基础分析之描述符
五、利用描述符自定义 @property
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <code> class Lazyproperty: def __init__(self, func): self.func = func def __get__(self, instance, owner): print ( "===> Lazypropertt.__get__ 参数: instance = {}, owner = {}" .format(instance, owner)) if instance is None: return self res = self.func(instance) setattr(instance, self.func.__name__, res) return self.func(instance) # def __set__(self, instance, value): # pass class Room: def __init__(self, name, width, height): self.name = name self.width = width self.height = height # @property # area=property(area) @Lazyproperty # # area=Lazyproperty(area) def area(self): return self.width * self.height # @property 测试代码 # r = Room( "房间" , 2, 3) # print (Room.__dict__) # {..., 'area' : <property object at 0x7f8b42de5ea8>,} # print (r.area) # 6 # r2 = Room( "房间2" , 2, 3) # print (r2.__dict__) # { 'name' : '房间2' , 'width' : 2, 'height' : 3} # print (r2.area) # print (Room.area) # <__main__.Lazyproperty object at 0x7faabd589a58> r3 = Room( "房间3" , 2, 3) print (r3.area) print (r3.area) # 结果(只计算一次): # ===> Lazypropertt.__get__ 参数: instance = <__main__.Room object at 0x7fd98e3757b8>, owner = < class '__main__.Room' > # 6 # 6 </code> |
Python基础分析之描述符
六、property 补充
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <code> class Foo: @property def A(self): print ( "===> get A" ) @A.setter def A(self, val): print ( "===> set A, val = {}" .format(val)) @A.deleter def A(self): print ( "===> del A" ) f = Foo() f.A # ===> get A f.A = "a" # ===> set A, val = a del f.A # ===> del A class Foo: def get_A(self): print ( "===> get_A" ) def set_A(self, val): print ( "===> set_A, val = {}" .format(val)) def del_A(self): print ( "===> del_A" ) A = property(get_A, set_A, del_A) f = Foo() f.A # ===> get_A f.A = "a" # ===> set_A, val = a del f.A # ===> del_A </code> |
Python基础分析之描述符
到此这篇关于Python基础详解之描述符的文章就介绍到这了,更多相关Python描述符内容请搜索php教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持php教程!
注:关于Python之描述符的功能实例的内容就先介绍到这里,更多相关文章的可以留意