python描述符descriptor(一)
Python 描述符是一种创建托管属性的方法。每当一个属性被查询时,一个动作就会发生。这个动作默认是get,set或者delete。不过,有时候某个应用可能会有
更多的需求,需要你设计一些更复杂的动作。最好的解决方案就是编写一个执行符合需求的动作的函数,然后指定它在属性被访问时运行。一个具有这种功能的对象
称为描述符。描述符是python方法,绑定方法,super,property,staticmethod和classmethod的实现基础。
1.描述符协议
描述符descriptor就是一个表示属性值的对象,通过实现一个或多个__get__,__set__,__delete__方法,可以将描述符与属性访问机制挂钩,还可以自定义这些操作。
__get__(self,instance,own):用于访问属性,返回属性的值。instance为使用描述符的实例对象,own为实例所属的类。当通过类访问属性时,instance为None。
__set__(self,instance,value):设定属性值。
__delete__(self,instance):删除属性值。
2.描述符如何实现
class Descriptor(object):
def __get__(self, instance, owner):
print 'getting:%s'%self._name
return self._name
def __set__(self, instance, name):
print 'setting:%s'%name
self._name = name
def __delete__(self, instance):
print 'deleting:%s'%self._name
del self._name
class Person(object):
name = Descriptor()
一个很简单的描述符对象就产生了,现在可以对一个Person对象进行属性name的读取,设置和删除:
>>> p=Person()
>>> p.name='john'
setting:john
>>> p.name
getting:john
'john'
>>> del p.name
deleting:john
注意:描述符只能在类级别上进行实例化,不能通过在__init__()和其他方法中创建描述符对象来为每个实例创建描述符。
具有描述符的类使用的属性名称比实例上存储的属性名称具有更高的优先级。为了能让描述符在实例上存储值,描述符必须挑选一个与它本身所用名称不同的名称。
如上例,Person类初始化__init__函数为实例设置属性就不能用name名称了。
data描述符与none-data描述符:
如果实现了__get__和__set__就是一个data描述符,如果只有__get__就是一个non-data描述符。不同的效果在于data描述符总是替代在一个实例中的属性实现,
而non-data描述符由于没有set,在通过实例对属性赋值时,例如上面的p.name = 'hello',不会再调用__set__方法,会直接把实例属性p.name设为'hello'。
当然如果仅仅在__set__中raise AttributeError,仍然得到的是一个non-data的描述符。
描述符调用机制:
当查询一个对象的属性a.attr时,如果python发现attr是个描述符对象,如何读取属性取决于对象a:
直接调用:最简单的调用是直接使用代码调用描述符的方法,attr.__get__(a)
实例绑定:如果a是个实例对象,调用方法:type(a).__dict__['attr'].__get__(a,type(a))
类绑定:如果A是个类对象,调用方法:A.__dict__['attr'].__get__(None,A)
super绑定:如果a是个super实例,那么super(B,obj).m()通过查询obj.__class__.__mro__找到B的基类A,然后执行A.__dict__['m'].__get__(obj,obj.__class__)
3.执行属性类型检查的描述符
class TypedProperty(object):
def __init__(self,name,attr_type,default=None):
self.name='_'+name
self.type=attr_type
self.default=default if default else attr_type()
def __get__(self,instance,own):
return getattr(instance,self.name,self.default)
def __set__(self,instance,value):
if not isinstance(value,self.type):
raise TypeError,'Must be %s'%self.type
setattr(instance,self.name,value)
def __delete__(self,instance):
raise AttributeError('Can not delete attribute')
class Foo(object):
name=TypedProperty('name',str)
num=TypedProperty('num',int,37)
上述描述符可以对属性的类型进行检查,如果name属性不设为str类型或者num不设为int类型,就会报错:
>>> f.name=21
TypeError: Must be <type 'str'>
而且禁止对属性进行删除操作:
>>> del f.name
AttributeError: Can not delete attribute
f.name 隐形的调用type(f).__dict__['name'].__get__(f,Foo),即Foo.name.__get__(f,Foo)。
上述描述符实际是存储在实例上的,name通过setattr(f,_name,value)存储在f._name上,num存储在f._num上,这也是加下划线的原因,
否则描述符名称name会和实例属性name发生冲突,描述符属性f.name会覆盖掉实例属性f.name。
python描述符descriptor(一)的更多相关文章
- Python 描述符(descriptor) 杂记
转自:https://blog.tonyseek.com/post/notes-about-python-descriptor/ Python 引入的“描述符”(descriptor)语法特性真的很黄 ...
- python描述符 descriptor
descriptor 在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor通常用来改 ...
- python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解
1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...
- Python描述符 (descriptor) 详解
1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如 ...
- Python 描述符(Descriptor) 附实例
在 Python 众多原生特性中,描述符可能是最少被自定义的特性之一,但它在底层实现的方法和属性却无时不刻被使用着,它优雅的实现方式体现出 Python 简洁之美. 定义 一个描述符是一个有" ...
- Python 描述符 (descriptor)
1.什么是描述符? 描述符是Python新式类的关键点之一,它为对象属性提供强大的API,你可以认为描述符是表示对象属性的一个代理.当需要属性时,可根据你遇到的情况,通过描述符进行访问他(摘自Pyth ...
- python描述符descriptor(二)
python内置的描述符 python有些内置的描述符对象,property.staticmethod.classmethod,python实现如下: class Property(object): ...
- 【python】描述符descriptor
开始看官方文档,各种看不懂,只看到一句Properties, bound and unbound methods, static methods, and class methods are all ...
- 杂项之python描述符协议
杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...
随机推荐
- java_Cookie_example(你上次访问的时间)
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, ...
- 如何在mac上創建txt文档
文件編輯(Mac下的記事本),shift + command + T 進入純文字編輯模式!
- 一个小例子讲讲jsonp
1.何为jsonp(json with padding) json我们都知道并用过.那么jsonp呢,呃,好像听过,但没用过.很久以来楼主也只是听过这个名词而已.直到今晚楼主看到一篇文章(http:/ ...
- 在 iOS 8 中使用模糊效果
在 iOS 7 出來一個背景模糊的效果, Apple 官方的 sample code 則有提供怎麼使用 vImage, Quartz 來實作這個效果.接著在 iOS 8 出來之後,則提供了 UIVi ...
- Bootstrap的Affix与ScrollSpy用法 bootstrap-scrollspy && bootstrap-dropdown
bootstrap-scrollspy && bootstrap-dropdown Bootstrap的Affix与ScrollSpy用法 http://9iphp.com/web/j ...
- 利用JS_SDK实现QQ第三方登录
前言 现如今,第三方登录已成为大部分网站必备的一项基础技能,引入时髦的第三方登录不仅能帮你吸引更多的用户,也让你的网站可以充分利用其他大型网站的用户资源.本次教程将让你的网站最快捷便利地引入QQ登录. ...
- c++算法联系,冒泡排序,bubble sort,插入排序,insert sort,
#include <iostream.h> #define MAX 100 void dispaly(int a[],int n) { for(int i=0;i<n;i+ ...
- lshw 命令(查看硬件信息)
帮助 $ lshw -h Hardware Lister (lshw) - B.02.16 usage: lshw [-format] [-options ...] lshw -version -ve ...
- 常用CSS技巧资料收集
1.重置浏览器的字体大小 重置浏览器的默认值 ,然后重设浏览器的字体大小你可以使用雅虎的用户界面重置的CSS方案 ,如果你不想下载9MB的文件,代码如下: body,div,dl,dt,dd,ul, ...
- 【JDK源码系列】ConcurrentHashMap
并发永远是高性能的话题,而并发容器又是java中重要的并发工具,所以今天我们来分析一下Concurrent包中ConcurrentHashMap(以下简称Chashmap).普通容器在某些并发情况下的 ...