Python之描述符的功能实例
感兴趣的小伙伴,下面一起跟随php教程的雯雯来看看吧!
一、描述符定义
描述符
这篇文章主要为大家详细介绍了Python之描述符的功能实例,具有一定的参考价值,可以用来参考一下。
感兴趣的小伙伴,下面一起跟随php教程的雯雯来看看吧!
一、描述符定义
描述符是一种类,我们把实现了__get__()、__set__()和__delete__()中的其中任意一种方法的类称之为描述符。
描述符的作用是用来代理一个类的属性,需要注意的是描述符不能定义在被使用类的构造函数中,只能定义为类的属性,它只属于类的,不属于实例,我们可以通过查看实例和类的字典来确认这一点。
描述符是实现大部分Python类特性中最底层的数据结构的实现手段,我们常使用的@classmethod、@staticmethd、@property、甚至是__slots__等属性都是通过描述符来实现的。它是很多高级库和框架的重要工具之一,是使用到装饰器或者元类的大型框架中的一个非常重要组件。
如下示例一个描述符及引用描述符类的代码:
代码如下:
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}
Python基础分析之描述符
其中,Descriptors类就是一个描述符,Person是使用描述符的类。
类的__dict__属性是类的一个内置属性,类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里。
在输出描述符的变量时,会调用描述符中的__get__方法,在设置描述符变量时,会调用描述符中的__set__方法。
二、描述符的种类和优先级
描述符分为数据描述符和非数据描述符。
至少实现了内置__set__()和__get__()方法的描述符称为数据描述符;实现了除__set__()以外的方法的描述符称为非数据描述符。
描述符的优先级的高低顺序:类属性 > 数据描述符 > 实例属性 > 非数据描述符 > 找不到的属性触发__getattr__()。
在上述“描述符定义”章节的例子中,实例person的属性优先级低于数据描述符Descriptors,所以在赋值或获取值过程中,均调用了描述符的方法。
代码如下:
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
Python基础分析之描述符
类属性 > 数据描述符
代码如下:
# 类属性 > 数据描述符
# 在调用类属性时,原来字典中的数据描述法被覆盖为 XX-XX
print(University.__dict__) # {..., 'name': <__main__.Descriptors object at 0x7ff8c0eda278>,}
University.name = "XX-XX"
print(University.__dict__) # {..., 'name': 'XX-XX',}
Python基础分析之描述符
数据描述符 > 实例属性
代码如下:
# 数据描述符 > 实例属性
# 调用时会现在实例里面找,找不到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
Python基础分析之描述符
下面是测试 实例属性、 非数据描述符、__getattr__ 使用代码
代码如下:
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))
Python基础分析之描述符
实例属性 > 非数据描述符
代码如下:
# 实例属性 > 非数据描述符
# 在创建实例的时候,会在属性字典中添加 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'}
Python基础分析之描述符
非数据描述符 > 找不到的属性触发__getattr__
代码如下:
# 非数据描述符 > 找不到的属性触发__getattr__
# 找不到 name1 使用 __getattr__
un3 = University("xu3")
print(un3.name1) # ---> 查找 item = name1
Python基础分析之描述符
三、描述符的应用
使用描述符检验数据类型
代码如下:
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}
Python基础分析之描述符
四、描述符 + 类装饰器 (给 Person类添加类属性)
类装饰器,道理和函数装饰器一样
代码如下:
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)
Python基础分析之描述符
使用描述符和类装饰器给 Person类添加类属性
代码如下:
"""
描述符 + 类装饰器
"""
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}
Python基础分析之描述符
五、利用描述符自定义 @property
代码如下:
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
Python基础分析之描述符
六、property 补充
代码如下:
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
Python基础分析之描述符
到此这篇关于Python基础详解之描述符的文章就介绍到这了,更多相关Python描述符内容请搜索php教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持php教程!
注:关于Python之描述符的功能实例的内容就先介绍到这里,更多相关文章的可以留意