Python描述符入门
什么是Python描述符?
Python描述符是一种实现了特定协议的对象,允许自定义属性访问和赋值的行为,是Python属性的核心机制之一。描述符常用于创建高级对象,例如ORM(对象关系映射)模型、表单验证和属性缓存等。在Python中,一个描述符必须实现以下方法:
__get__(self, instance, owner=None)
:访问描述符时调用的方法,返回属性的值。__set__(self, instance, value)
:设置描述符时调用的方法,设置属性的值。__delete__(self, instance)
:删除描述符时调用的方法。
描述符的使用方法
使用描述符,需要创建一个类,并在其中定义上述方法。当某个属性被定义为一个描述符实例时,该实例的相关方法将被调用来访问和修改属性。以下是一个实现描述符的例子:
class Descriptor:
def __init__(self, name=None):
self.name = name
def __get__(self, instance, owner=None):
if instance:
return instance.__dict__.get(self.name)
return self
def __set__(self, instance, value):
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
上述描述符方法中,将属性的名称保存在name
参数中。__get__
方法的参数instance
指向拥有该属性的对象实例,owner
参数指向对象的类(可选)。在返回属性值时,使用instance.__dict__.get(self.name)
获取该实例中属性的值。__set__
方法用来设置属性值,使用instance.__dict__[self.name] = value
进行设置操作。__delete__
方法用于删除属性,在这个例子中使用del instance.__dict__[self.name]
来删除实例中的属性。
可以使用以上定义的描述符来定义一个类:
class Person:
name = Descriptor('name')
age = Descriptor('age')
使用上述类创建一个对象并尝试设置属性:
p = Person()
p.name = "Jack"
p.age = 20
print(p.name) # 输出Jack
print(p.age) # 输出20
描述符的应用
下面介绍两个描述符实现的例子:
描述符给属性设置只读属性
在这个例子中,我们将实现描述符来给某个属性设置只读属性。在__set__
方法中,如果尝试修改值,将触发AttributeError
异常。
class ReadOnlyDescriptor:
def __init__(self, name=None):
self.name = name
def __get__(self, instance, owner=None):
if instance:
return instance.__dict__.get(self.name)
return self
def __set__(self, instance, value):
raise AttributeError("Read Only Attribute")
def __delete__(self, instance):
del instance.__dict__[self.name]
class Person:
name = ReadOnlyDescriptor('name')
age = Descriptor('age')
测试代码如下:
p = Person()
p.name = "Jack"
p.age = 20
print(p.name) # 输出Jack
# 抛出异常
try:
p.name = "Lucy"
except AttributeError as e:
print(e)
# 输出20
print(p.age)
描述符实现缓存属性
在这个例子中,我们将实现一个描述符来缓存一些属性,避免重复计算。在__get__
方法中,如果值已经被设置过,就直接返回缓存的结果。否则计算结果并设为该属性的值,并将值保存在缓存变量cached_value
中。
class CacheDescriptor:
def __init__(self, func):
self.func = func
self.cached_value = None
def __get__(self, instance, owner=None):
if instance:
if self.cached_value is None:
self.cached_value = self.func(instance)
return self.cached_value
return self
def __set__(self, instance, value):
self.cached_value = value
def __delete__(self, instance):
self.cached_value = None
class Circle:
def __init__(self, radius):
self.radius = radius
@CacheDescriptor
def area(self):
print("calculating area")
return 3.14 * self.radius ** 2
测试代码如下:
c = Circle(10)
print(c.area) # 计算面积,并输出314.0
print(c.area) # 直接输出314.0,无需重复计算
c.radius = 5 # 修改属性后需要重新计算面积
print(c.area) # 计算新的面积,并输出78.5
结论
以上是Python描述符的基础知识和使用方法。描述符作为Python属性的核心机制之一,可以非常灵活的定义属性的访问和修改行为,实现各种高级功能。需要注意的是,描述符是Python高级语言的一部分,初学者需要更多的实践积累经验才能熟练掌握。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 描述符(Descriptor)入门 - Python技术站