Python描述符的使用
Python描述符的使用
前言
作为一位python的使用者,你可能使用python有一段时间了,但是对于python中的描述符却未必使用过,接下来是对描述符使用的介绍
场景介绍
为了引入描述符的使用,我们先设计一个非常简单的类:
class Product():
    def __init__(self,name,quantity,price):
        self.name = name
        self.quantity = quantity
        self.price = price
这是一个商品类,存储该商品的名称,数量与价格。
对于一件商品,我们一般会期望它的数量和价格不会是负值,为了避免这种情况,我们可以在初始化的时候加一些判断,比如下面这样:
class Product():
    def __init__(self,name,quantity,price):
        self.name = name
        if quantity<0:
            raise ValueError('quantity must be >= 0')
        self.quantity = quantity
        if quantity<0:
            raise ValueError('price must be >= 0')
        self.price = price
但是这样还会有一个弊端就是这样的判断只是加在了初始化的时候,然后在之后对类的实例的属性进行赋值的时候还是无法保证赋的值是大于0 的
于是我们可以使用‘特性’来解决这个问题:
class Product():
    def __init__(self,name,quantity,price):
        self.name = name
        self.quantity = quantity
        self.price = price
    @property
    def quantity(self):
        return self._quantity
    @quantity.setter
    def quantity(self,value):
        if value < 0:
            raise ValueError('quantity must be >= 0')
        else:
            self._quantity = value
    @property
    def price(self):
        return self._price
    @price.setter
    def price(self, value):
        if value < 0:
            raise ValueError('price must be >= 0')
        else:
            self._price = value
book = Product('mybook',6,30)
print(book.quantity)
这里的@property和@quantity.setter是两个装饰器,它可以设置属性的读与写,就相当于读写属性,但其实是执行一个函数,具体有关特性的介绍,可以再自行查找,这里主要是为了引出描述符。
通过特性,可以完成为属性赋值时添加判断。但是当一个类中有更多的属性,很多属性同样需要添加非负数赋值的检查的时候,使用特性这种方式就会显得过于累赘,会有很多的代码重复,也会添加很多装饰器,这时就可以使用描述符来解决这个问题。
使用描述符
首先看一下描述符的概念
描述符就是一个“绑定行为“的对象属性,在描述符协议中,它可以通过方法充写属性的访问。这些方法有get(),set(),delete().如果这些方法中任何一个被定义在一个对象中,这个对象就是一个描述符
(这几个方法是特殊方法,双下划线由于转换未显示)
我们先把上文中的商品类按照使用描述符进行修改:
class NotNegative():
    def __init__(self,name):
        self.name = name
    def __set__(self, instance, value):
        if value < 0:
            raise ValueError(self.name+' must be >= 0')
        else:
            instance.__dict__[self.name] = value
class Product():
    quantity = NotNegative('quantity')
    price = NotNegative('price')
    def __init__(self,name,quantity,price):
        self.name = name
        self.quantity = quantity
        self.price = price
book = Product('mybook',2,5)
NotNegative是描述符类,它是Product类的类属性
在该例子中,如果执行book.quantity=3,解释器会先查找实例属性,发现有quantity属性,但是解释器又发现同样有一个类属性是描述符,于是解释器最终会选择走描述符这条路。然后因为是描述符,于是会执行描述符中的set特殊方法。相关属性的查找顺序可以参考https://www.cnblogs.com/Jimmy1988/p/6808237.html
描述符中的set特殊方法的参数有为
self :是描述符实例
instance :是相当于例子中的实例book
value :就是要赋予的值
由于这些属性对于取值没有什么特殊的要求所以例子中没有实现get特殊方法。
get方法同样有3个参数self, instance, owner。self,instance与set中的相同,owner为例子中的Product类
接下来主要看一下描述符set方法中else部分进行的操作
instance.__dict__[self.name] = value
通过调用book实例的dict,直接为dict中的属性赋值,这也是参数中传入实例的一个重要原因。由于描述符对象是作为类属性存在,所以可能会有很多个该类的对象访问,为了防止属性的覆盖,直接存入实例的属性中是妥当的。但这里不能为属性赋值的方式,不然就会陷入死循环当中。
对于数据描述符与非数据描述符,一个类,如果只定义了 get() 方法,而没有定义 set(), delete() 方法,则认为是非数据描述符; 反之,则成为数据描述符。
最后,本文是对描述符的使用做了简单的介绍与讲解,如需更加深入了解可以参考《流畅的Python》属性描述符部分
Python描述符的使用的更多相关文章
- 杂项之python描述符协议
		
杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...
 - python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解
		
1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...
 - 【转载】Python 描述符简介
		
来源:Alex Starostin 链接:www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 关于Python@修饰符的文章可 ...
 - python描述符descriptor(一)
		
Python 描述符是一种创建托管属性的方法.每当一个属性被查询时,一个动作就会发生.这个动作默认是get,set或者delete.不过,有时候某个应用可能会有 更多的需求,需要你设计一些更复杂的动作 ...
 - python描述符 descriptor
		
descriptor 在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor通常用来改 ...
 - Python描述符 (descriptor) 详解
		
1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如 ...
 - python描述符和属性查找
		
python描述符 定义 一般说来,描述符是一种访问对象属性时候的绑定行为,如果这个对象属性定义了__get__(),__set__(), and __delete__()一种或者几种,那么就称之为描 ...
 - Iterator Protocol - Python 描述符协议
		
Iterator Protocol - Python 描述符协议 先看几个有关概念, iterator 迭代器, 一个实现了无参数的 __next__ 方法, 并返回 '序列'中下一个元素,在没有更多 ...
 - Python描述符以及Property方法的实现原理
		
Python描述符以及Property方法的实现原理 描述符的定义: 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实了__get__(),__set__(),__delete__()中 ...
 
随机推荐
- 正确重写hashcode hashcode与equals方法 集合元素如何判断是否相等 集合如何查看是否包含某个元素
			
首先记住两句话 相等的两个对象,即equals(Object)方法判断两个对象相等,那么他们必须要有相同的hashcode hashcode相同的两个对象,他们可能相同,也可能不相同 简单地说可以这么 ...
 - python三大神器之virtualenv
			
virtualenv virtualenv用来管理python项目环境,隔离出一个只属于这个项目的虚拟python环境(windows和Linux用法一样). 首先你需要安装virtualenv模块 ...
 - input的三个属性autocomplete、autocapitalize和autocorrect
			
下面的input的三个属性是H5新增的属性 <input type="text" class="input-search" placeholder=&qu ...
 - 【Bootstrap系列】详解Bootstrap-table
			
本篇文章将与大家分享bootstrap-table插件,借助于它实现基本的增删改查,导入导出,分页,父子表等. 至于其他技术,如冻结表头,列排列,行拖动,列拖动等,会在后续文章中与大家分享. 一 ...
 - SHELL脚本--变量(基础)
			
bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html 变量存在于内存中.假设变量str,设置或修改变量属性时,不带$ ...
 - Python 的反射机制
			
什么叫做反射 利用字符串的形式去对象(模块)中操作(查找/添加/获取/删除)成员,一种基于字符串的事件驱动. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型.然后,可以 ...
 - nginx详解反向代理、负载均衡、LNMP架构上线动态网站(week4_day1_part1)-技术流ken
			
nginx介绍 Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”,是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理 ...
 - [转]MySQL查询缓存清空
			
本文转自:https://www.cnblogs.com/wangyiwei/p/7765457.html 可以通过下面的SQL查看当前查询缓存相关参数状态: SHOW VARIABLES LIK ...
 - VM虚拟机Linux和主机数据传输
			
虚拟机 Linux CentOS7 vm和主机通信是利用 vm tools 点击安装 点击后系统内有一个 打开 把 拖到桌面 打开终端 cd /home/whoami/桌面 ls 查看这个.tar. ...
 - 雪碧图和如何实现浏览器中title的小图标
			
background-position 雪碧图 我们的html和css中有三个属性可以向服务器发送请求 ser href url 2.overflow (1) 值hidden 超出就隐藏 (2)值sc ...