来源:Alex Starostin

链接:www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/

关于Python@修饰符的文章可以看:https://my.oschina.net/shyl/blog/626490

简介

Python 2.2 引进了 Python 描述符,同时还引进了一些新的样式类,但是它们并没有得到广泛使用。Python 描述符是一种创建托管属性的方法。除了其他优点外,托管属性还用于保护属性不受修改,或自动更新某个依赖属性的值。

描述符增加了对 Python 的理解,改善了编码技能。本文介绍了描述符协议,并演示了如何创建和使用描述符。

描述符协议

Python 描述符协议 只是一种在模型中引用属性时指定将要发生事件的方法。它允许编程人员轻松、有效地管理属性访问:

  1、set    2、get     3、delete

在其他编程语言中,描述符被称作 setter 和 getter,而公共函数用于获得 (Get) 和设置 (Set) 一个私有变量。Python 没有私有变量的概念,而描述符协议可以作为一种 Python 的方式来实现与私有变量类似的功能。

总的来说,描述符就是一个具有绑定行为的对象属性,其属性访问将由描述符协议中的方法覆盖。这些方法为 __get__、__set__ 和 __delete__。如果这些方法中的任何一个针对某个对象定义,那么它就被认为是一个描述符。通过 清单 1 进一步了解这些方法。

清单 1. 描述符方法

__get__(self, instance, owner)

__set__(self, instance, value)

__delete__(self, instance)      

其中:

__get__ 用于访问属性。它返回属性的值,或者在所请求的属性不存在的情况下出现 AttributeError 异常。

__set__ 将在属性分配操作中调用。不会返回任何内容。

__delete__ 控制删除操作。不会返回内容。

需要注意,描述符被分配给一个类,而不是实例。修改此类,会覆盖或删除描述符本身,而不是触发它的代码。

需要使用描述符的情况

考虑 email 属性。在向该属性分配值之前,需要对邮件格式进行检验。该描述符允许通过一个正则表达式处理电子邮件,然后对格式进行检验后将它分配给一个属性。

在其他许多情况下,Python 协议描述符控制对属性的访问,如保护 name 属性。

创建描述符

您可以通过许多方式创建描述符:

  • 创建一个类并覆盖任意一个描述符方法:__set__、__ get__ 和 __delete__。当需要某个描述符跨多个不同的类和属性,例如类型验证,则使用该方法。

  • 使用属性类型,这种方法可以更加简单、灵活地创建描述符。

  • 使用属性描述符,它结合了属性类型方法和 Python 描述符。

以下示例在其操作方面均相似。不同之处在于实现方法。

使用类方法创建描述符

class Descriptor(object):

    def __init__(self):
self._name = '' 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.title() def __delete__(self, instance):
print "Deleting: %s" %self._name
del self._name class Person(object):
name = Descriptor()

 使用这些代码并查看输出:

>>> user = Person()
>>> user.name = 'john smith'
Setting: john smith
>>> user.name
Getting: John Smith
'John Smith'
>>> del user.name
Deleting: John Smith

通过以下方法覆盖父类的 __set__()、__get__() 和 __delete__() 方法,创建一个描述符类:

  • get 将输出 Getting

  • delete 将输出 Deleting

  • set 将输出 Setting

并在分配之前将属性值修改为标题title(第一个字母大写,其他字母为小写)。这样做有助于存储和输出名称

大写转换同样可以移动到 __get__() 方法。_value 有一个初始值,并根据 get 请求转换为标题。

使用属性类型创建描述符

虽然上面中定义的描述符是有效的且可以正常使用,但是还可以使用属性类型的方法。通过使用 property(),可以轻松地为任意属性创建可用的描述符。创建 property() 的语法是 property(fget=None, fset=None, fdel=None, doc=None),其中:

  • fget:属性获取方法

  • fset:属性设置方法

  • fdel:属性删除方法

  • doc:docstring

使用属性重写该例子,如 下所示。

class Person(object):
def __init__(self):
self._name = '' def fget(self):
print "Getting: %s" % self._name
return self._name def fset(self, value):
print "Setting: %s" % value
self._name = value.title() def fdel(self):
print "Deleting: %s" %self._name
del self._name
name = property(fget, fset, fdel, "I'm the property.") 使用该代码并查看输出: >>> user = Person()
>>> user.name = 'john smith'
Setting: john smith
>>> user.name
Getting: John Smith
'John Smith'
>>> del user.name
Deleting: John Smith

 

显然,结果是相同的。注意,fget、fset 和 fdel 方法是可选的,但是如果没有指定这些方法,那么将在尝试各个操作时出现一个 AttributeError 异常。例如,声明 name 属性时,fset 被设置为 None,然后开发人员尝试向 name 属性分配值。这时将出现一个 AttributeError 异常。

这种方法可以用于定义系统中的只读属性:

 

name = property(fget, None, fdel, "I'm the property")
user.name = 'john smith' 输出为: Traceback (most recent call last):
File stdin, line 21, in mоdule
user.name = 'john smith'
AttributeError: can't set attribute

使用属性修饰符创建描述符

可以使用 Python 修饰符创建描述符,如 下 所示。Python 修饰符是对 Python 语法的特定修改,能够更方便地更改函数和方法。在本例中,将修改属性管理方法。在 developerWorks 文章 Decorators make magic easy 中寻找更多有关应用 Python 修饰符的信息。

class Person(object):

    def __init__(self):
self._name = '' @property
def name(self):
print "Getting: %s" % self._name
return self._name @name.setter
def name(self, value):
print "Setting: %s" % value
self._name = value.title() @name.deleter
def name(self):
print ">Deleting: %s" % self._name
del self._name

  

在运行时创建描述符

前面的所有例子都使用了 name 属性。该方法的局限性在于需要对各个属性分别覆盖 __set__()、__get__() 和 __delete__()。清单 5 提供了一个可能的解决方案,帮助开发人员在运行时添加 property 属性。该解决方案使用属性类型构建数据描述符。

使用属性修饰符创建描述符

  

class Person(object):

    def addProperty(self, attribute):
# create local setter and getter with a particular attribute name
getter = lambda self: self._getProperty(attribute)
setter = lambda self, value: self._setProperty(attribute, value) # construct property attribute and add it to the class
setattr(self.__class__, attribute, property(fget=getter, \
fset=setter, \
doc="Auto-generated method")) def _setProperty(self, attribute, value):
print "Setting: %s = %s" %(attribute, value)
setattr(self, '_' + attribute, value.title()) def _getProperty(self, attribute):
print "Getting: %s" %attribute
return getattr(self, '_' + attribute) 让我们运行这段代码: >>> user = Person()
>>> user.addProperty('name')
>>> user.addProperty('phone')
>>> user.name = 'john smith'
Setting: name = john smith
>>> user.phone = '12345'
Setting: phone = 12345
>>> user.name
Getting: name
'John Smith'
>>> user.__dict__
{'_phone': '12345', '_name': 'John Smith'}

 

这将在运行时创建 name 和 phone 属性。它们可以根据相应的名称进行访问,但是按照 _setProperty 方法中的定义,将在对象名称空间目录中存储为 _name 和 _phone。基本上,name 和 phone 是对内部的 _name 和 _phone 属性的访问符。

当开发人员尝试添加 name property 属性时,您可能对系统中的 _name 属性存在疑问。实际上,它将用新的 property 属性覆盖现有的 _name 属性。这些代码允许控制如何在类内部处理属性。

 

  

【转载】Python 描述符简介的更多相关文章

  1. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  2. python描述符 descriptor

    descriptor 在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor通常用来改 ...

  3. 杂项之python描述符协议

    杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...

  4. python描述符descriptor(一)

    Python 描述符是一种创建托管属性的方法.每当一个属性被查询时,一个动作就会发生.这个动作默认是get,set或者delete.不过,有时候某个应用可能会有 更多的需求,需要你设计一些更复杂的动作 ...

  5. Python描述符的使用

    Python描述符的使用 前言 作为一位python的使用者,你可能使用python有一段时间了,但是对于python中的描述符却未必使用过,接下来是对描述符使用的介绍 场景介绍 为了引入描述符的使用 ...

  6. Python描述符 (descriptor) 详解

    1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如 ...

  7. python描述符和属性查找

    python描述符 定义 一般说来,描述符是一种访问对象属性时候的绑定行为,如果这个对象属性定义了__get__(),__set__(), and __delete__()一种或者几种,那么就称之为描 ...

  8. Iterator Protocol - Python 描述符协议

    Iterator Protocol - Python 描述符协议 先看几个有关概念, iterator 迭代器, 一个实现了无参数的 __next__ 方法, 并返回 '序列'中下一个元素,在没有更多 ...

  9. Python描述符以及Property方法的实现原理

    Python描述符以及Property方法的实现原理 描述符的定义: 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实了__get__(),__set__(),__delete__()中 ...

随机推荐

  1. css 笔记

    外边距合并 当一个元素出现在另一个元素的上面时,第一个元素的下外边距和第二个元素的上外边距会产生合并,两个盒子之间的上下间距为大的数值. 当一个子元素包含在另外一个父元素(假设没有内边距 没有边框), ...

  2. ios framework 简单制作

    在制作过程中遇到的一些问题跟大家分享下,直接上步骤 制作库有分模拟器框架和真机矿机  如果报错x86_64什么的字眼就是库里面没有包含模拟器框架 模拟器:iPhone4s~5 : i386 iPhon ...

  3. MySQL数据库8 -子查询,联合查询

    一 使用IN关键字的子查询 问题: 查询游戏类型是'棋牌类' 的游戏的分数信息 - 游戏分数表中并未包含游戏类型信息 思路一:采用链接查询 思路二: 分两步进行,首先找到所以'棋牌类'游戏的编号,再以 ...

  4. 关于css的新思考

    因为被派去协助别的组,有机会写了一下react,发现ICE做的那一个套件用来搭建后台系统真的太给力了(插一句必入table组件其实是可以把删除添加座位基础方法加进去的).因为看了demo的代码以及对于 ...

  5. 更新UI界面的四种方法

    一.runOnUiThread(new Runnable()): 二.Handler的sendMessage()系列: 三.Handler的post(): 四.View的post():

  6. Best Coder Round#25 1003 树的非递归访问

    虽然官方解释是这题目里的树看作无向无环图,从答案来看还是在“以1作为根节点”这一前提下进行的,这棵树搭建好以后,从叶节点开始访问,一直推到根节点即可——很像动态规划的“自底向上”. 但这棵树的搭建堪忧 ...

  7. C++笔试题

    平时学术必须用Python多啊,但校招笔试绕不开语言基础,非cs科班小弱临阵整理些C++题备考.很弱很苦逼... 一.指针 1.二维数组指针 #include<stdio.h> int m ...

  8. 【C编译器】MinGw安装与使用(调试问题待续)

    不想装vs2005之类的,想要一个轻量级的C语言编译器,希望将焦点放在如何写好代码上: 本人信奉:代码质量是靠设计和检视保证的,不是靠调试: 1.安装MinGW http://www.mingw.or ...

  9. loadRunner录制脚本常见问题及解决方法

    1.是用IE9录制IE浏览器异常关闭 系统:win7 LR:11 浏览器:IE9 lr使用IE9录制脚本时,浏览器异常关闭且lr报the recording of the application wa ...

  10. BZOJ 2743 树状数组

    不能用分块. #include <bits/stdc++.h> using namespace std; ; struct Info{int l,r,Id;}Q[Maxn]; int a[ ...