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核心编程,把后面的习题都做一下.
随机推荐
- 动态规划(DP),模拟
题目链接:http://poj.org/problem?id=1088 Memory: 252KTime: 16MSLanguage: C++Result: Accepted 解题报告: 1.lm[i ...
- cmake安装的软件要怎么卸载
找到make install之后产生的这个文件install_manifest.txt里面有安装的所有东西的路径,删除它们即可.参考命令:cat install_manifest.txt | sudo ...
- Codeforces Round #366 (Div. 2) B
Description Peter Parker wants to play a game with Dr. Octopus. The game is about cycles. Cycle is a ...
- ajax验证表单元素规范正确与否 ajax展示加载数据库数据 ajax三级联动
一.ajax验证表单元素规范正确与否 以用ajax来验证用户名是否被占用为例 1创建表单元素<input type="text" id="t"> 2 ...
- linq的创建 和 数据的增删改查
1.linq创建之前,一定要在sql做好数据表的主外键关系. 2.linq文件是以.dbml结尾,一般一个数据库的名字就是一个linq的名字 3,以实例来演示增删改查 数据库的名字为linq,里面有两 ...
- 免费PHP WEB环境套件介绍
PHPNOW--Apache + PHP + MySQL(windows) easyphp--Apache + PHP + MySQL+phpmyadmin(windows) xampp(中文站点)- ...
- 计算5的阶乘并在JSP页面输出
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- PHP中的替代语法(冒号、endif、endwhile、endfor)
我们经常在wordpress一类博客程序的模板里面看到很多奇怪的PHP语法,比如: <?php if(empty($GET_['a'])): ?> <font color=" ...
- Java EE 锚、表格用法
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- JAVA查找--[二分查找]
package com.array; public class BinaryFind { /* * 项目名称:二分查找 ; * 项目要求:用JAVA对数组进行查找,并运用快速查找算法; * 作者:Se ...