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核心编程,把后面的习题都做一下.
随机推荐
- 使用Keil的MicroLIB时自动设置堆大小——玩嵌入式以来最高难度
Keil编译项目,如果使用微库MicroLIB,就可以使用malloc.微库内部位置一个堆管理模块.芯片的RAM大小是固定了的,前面分为全局变量,后面分给堆和栈,这是一般开发方式.但是我们在开发项目的 ...
- ZOJ 3593 One Person Game
One Person Game Time Limit: 2 Seconds Memory Limit: 65536 KB There is an interesting and simple ...
- Bootstrap——基本模板
<!DOCTYPE html><html lang="zh-cn"> <head> <meta charset="utf ...
- 【LTE基础知识】SGLTE, SVLTE, CSFB, VoLTE
4G网络下实现语音通话功能的技术共有三种--VoLTE.SGLTE(GSM /LTE同步并发)和CSFB(电路域回落).简单来说: VoLTE就是语音数据都在4G通道内完成: SGLTE是语音走2G通 ...
- VC++获取计算机Hardware Information (CPU ID, MainBoard Info, Hard Disk Serial, System Information)
转载:http://blog.csdn.net/yapingxin/article/details/50107799 转载:http://zhidao.baidu.com/link?url=A5K6N ...
- Oracle中如何使用REGEXP_SUBSTR函数
REGEXP_SUBSTR函数格式如下: function REGEXP_SUBSTR(String, pattern, position, occurrence, modifier) __srcst ...
- 用于 ‘Suse‘ Linux 包管理的 Zypper 命令大全
SUSE( Software and System Entwicklung,即软件和系统开发.其中‘entwicklung‘是德语,意为开发)Linux 是由 Novell 公司在 Linux 内核基 ...
- linux内核中的GPIO系统之(1):软件框架
一.前言 作为一个工作多年的系统工程师,免不了做两件事情:培训新员工和给新员工分配任务.对于那些刚刚从学校出来的学生,一般在开始的时候总是分配一些非常简单的任务,例如GPIO driver.LED d ...
- [HDOJ3308]LCIS(线段树,区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题意:给定n个数,两个操作: U A B:将位置A的数值改成B Q A B:查询[A,B]内最长 ...
- HIP-HOP 漫画家 Skottie Young
http://blog.sina.com.cn/s/blog_67e59b160100v9ib.html 以上是部分预览图! 下载地址: 29 MB= 127 张 yy语 ...