Python核心编程-描述符
python中,什么描述符。描述符就是实现了"__get__”、“__set__”或”__delete__” 方法中至少一个的对象。什么是非数据描述符,就是实现了__get__方法的对象,也就是初始化后,就只能读。数据描述符就是实现了__get__和__set__方法的对象,也就是说这个属性可读可重新赋值。
看一下Python核心编程中描述符的例子:
class DevNull2(object):
def __get__(self, obj, typ=None):
print 'Accessing attribute... ignoring'
def __set__(self, obj, val):
print 'Attempt to assign %r... ignoring' % (val) class C2(object):
foo = DevNull2()
c2 = C2()
c2.foo = 'bar'
这里DevNull2就是一个描述符,还有,下面的c2.foo的赋值并不是将DevNull2这个替换,因为Devnull2是一个描述符,所以,这里相当于代替了foo的属性值,在进行赋值操作的时候,会走DevNull2中的__set__方法。为什么描述符可以代表对象属性也就是为什么访问属性时调用的是__set__,__get__方法也不是访问的属性。这里需要了解属性解析的执行方式,对于对象来说属性解析机制在object.__getattribute__()方法中,因为对每个属性的实例都会调用到这个特殊的方法。这个方法被用来查找类的属性,同时也是你的一个代理,调用它可以进行属性的访问等操作回顾一下上面的原型,如果一个实例调用了__get__()方法,这就可能传入了一个类型或类的对象。举例来说,给定类 X 和实例 x, x.foo 由__getattribute__()转化成:
type(x).__dict__['foo'].__get__(x, type(x))
如果类调用了__get__()方法,那么 None 将作为对象被传入(对于实例, 传入的是 self):
X.__dict__['foo'].__get__(None, X)
优先级的排序:
- 类属性
- 数据描述符
- 实例属性
- 非数据描述符
- 默认为__getattr__()
在优先级链中,类字典中发现的数据描述符的优先级高于实例变量,实例变量优先级高于非数据描述符,如果提供了getattr(),优先级链会为getattr()分配最低优先级。对于一个给定的对象类,可以通过自定义__getattribute__方法来重写优先级链。
另外一个例子来说明怎么使用描述符
class TypedProperty(object):
def __init__(self, key, typ, val=None):
print 'key :' , key
self.key = '_' + key
print 'typ :' , typ
self.typ = typ
print 'val :' , val
self.val = val if val else typ() def __get__(self, instance, cls):
print 'in __get__ ', self.key, self.typ, self.val, instance
return getattr(instance, self.key, self.val) def __set__(self, instance, value):
print 'in __set__ ', self.key, self.typ, self.val, value
if not isinstance(value, self.typ):
raise TypeError("Must be a %s" % self.typ)
setattr(instance, self.key, value) def __delete__(self, instance):
print 'in __delete__'
raise AttributeError("Can't delete attribute") class Foo(object):
name = TypedProperty("name", str)
num = TypedProperty("num", int, )
foo = Foo()
foo.num =
foo.num
结果:
key : name
typ : <type 'str'>
val : None
key : num
typ : <type 'int'>
val : 42
in __set__ _num <type 'int'> 42 12
in __get__ _num <type 'int'> 42 <__main__.Foo object at 0x7f371f94a310>
都能看出来,在描述符中的key属性就是属性的名,val是属性值。肯定有有人注意到在__init__()方法中,将key值设成了‘_’ + key,这里并不是一定要写成这样,这里的目的主要就是为了在__set__和__get__方法中的instance也就是Foo的实例中的属性不要与描述符中的key的形式一样,就是如果instance中的属性是num,描述符中的属性就不能写成num,要区分开,这里在前边放了一个‘_’来区分(可以用任何形式来区分,也就是'_'可以随便写成‘whatever’)。如果没有区分开,在调用foo.num = 12 的时候,走进__set__方法中,在setattr()方法中又调用了instantce中的key属性也就是又调用了foo.num,最终形成一个循环。导致maximum recursion depth exceeded while getting the str of an object
python提供更简介的方式(利用property()内建函数):
property(fget=None, fset=None, fdel=None, doc=None)
class HideX(object):
def __init__(self, x):
self.x = x
def get_x(self):
return ~self.__x
def set_x(self, x):
assert isinstance(x, int), '"x" must be an integer!'
self.__x = ~x
x = property(get_x, set_x)
inst = HideX()
print inst.x
inst.x =
print inst.x
也可以用set_x和get_x方法设置和获取属性。如果利用property()方法感觉太乱,也可以用@property
class HideX(object):
def __init__(self, x):
self.x = x
@property
def x():
def fget(self):
return ~self.__x
def fset(self, x):
assert isinstance(x, int), '"x" must be an integer!'
self.__x = ~x
return locals()
这时也就只能用inst.x来获取或者重新赋值了。
还可以利用下面的方法:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Python核心编程-描述符的更多相关文章
- python核心编程第二版笔记
python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d 提供调试输出1.2 –O 生成优化的字节码(生成 ...
- python核心编程--笔记
python核心编程--笔记 的解释器options: 1.1 –d 提供调试输出 1.2 –O 生成优化的字节码(生成.pyo文件) 1.3 –S 不导入site模块以在启动时查找pyt ...
- Python核心编程第二版(中文).pdf 目录整理
python核心编程目录 Chapter1:欢迎来到python世界!-页码:7 1.1什么是python 1.2起源 :罗萨姆1989底创建python 1.3特点 1.3.1高级 1.3.2面向 ...
- python核心编程--笔记(不定时跟新)(转)
的解释器options: 1.1 –d 提供调试输出 1.2 –O 生成优化的字节码(生成.pyo文件) 1.3 –S 不导入site模块以在启动时查找python路径 1.4 –v ...
- python核心编程笔记(转)
解释器options: 1.1 –d 提供调试输出 1.2 –O 生成优化的字节码(生成.pyo文件) 1.3 –S 不导入site模块以在启动时查找python路径 1.4 –v 冗 ...
- Python核心编程(第二版)PDF
Python核心编程(第二版) 目录 第1部分 Python核心第1章 欢迎来到Python世界1.1 什么是Python1.2 起源1.3 特点1.3.1 高级1.3.2 面向对象1.3.3 可升级 ...
- Python核心编程-闭包
百度搜了一下闭包的概念:简而言之,闭包的作用就是在外部函数执行完并返回后,闭包使得收机制不会收回函数所占用的资源,因为内部函数的执行需要依赖外函数中的变量.这是对闭包作用的非常直白的描述,不专业也不严 ...
- 学习《Python核心编程》做一下知识点提要,方便复习(一)
学习<Python核心编程>做一下知识点提要,方便复习. 计算机语言的本质是什么? a-z.A-Z.符号.数字等等组合成符合语法的字符串.供编译器.解释器翻译. 字母组合后产生各种变化拿p ...
- python核心编程(第二版)习题
重新再看一遍python核心编程,把后面的习题都做一下.
随机推荐
- zoj Abs Problem
Abs Problem Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge Alice and Bob is pl ...
- COGS502. 长路上的灯
502. 长路上的灯 ☆ 输入文件:light.in 输出文件:light.out 简单对比时间限制:1 s 内存限制:128 MB [题目描述] 在一条无限长的路上,有一排无限长的路 ...
- iis 没目录文件
方法一: <system.webServer> <directoryBrowse enabled="true"/> </system.webServe ...
- Hashtable与ConcurrentHashMap区别
Hashtable与ConcurrentHashMap区别 ConcurrentHashMap融合了hashtable和hashmap二者的优势. hashtable是做了同步的,是线性安全的,(2) ...
- [bzoj1051] [HAOI2006]受欢迎的牛 (Tarjan+缩点)
强连通图,缩点 Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C受 ...
- 命名空间std引用<iostream>时使用
所谓namespace,是指标识符的各种可见范围. C++标准程序库中的所有标识符都被定义于一个名为std的namespace中,这样命名空间std内定义的所有标识符都有效. 为什么把cout等放在s ...
- 第二课 android项目结构
- Ajax发送POST请求的心路历程
好多年前就在项目中用ajax实现了页面部分数据的发送,当时用的是GET方法. 这次用POST方法实现同样的功能,竟然花费了不少的时间! ① 关于JQuery ajax的配置项说明 url : 请求的u ...
- 机器学习——SVM详解(标准形式,对偶形式,Kernel及Soft Margin)
(写在前面:机器学习入行快2年了,多多少少用过一些算法,但由于敲公式太过浪费时间,所以一直搁置了开一个机器学习系列的博客.但是现在毕竟是电子化的时代,也不可能每时每刻都带着自己的记事本.如果可以掏出手 ...
- 【Asp.Net使用EasyUI】EasyUI combox实现联动
很多时候都会用到combox的联动效果,选择上一个combox的值就自动带出这个值对应的其它信息,比如省市联动,最近我也刚好遇到了类似的要求,是用EasyUI combobox 控件完成的,如果是A ...