来源: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. SimpleAdapter的使用

    SimpleAdapter的使用       SimpleAdapter是一个简单的适配器,该适配器也继承了BaseAdapter,对于布局是固定而言,使用简单适配器开发时非常简单了,由于Simple ...

  2. jQuery原生框架-----------------事件

    jQuery.extend({ // 绑定事件 addEvent: function( ele, type, fn ) { // ele不是DOM,type不是字符串,fn不是函数,打包打走 if( ...

  3. 一篇介绍java与js操作cookie的

    http://blog.csdn.net/xuweilinjijis/article/details/8651188

  4. macbook air 128g 磁盘清理

    使用 du 命令发现 ~/Library/Developer/Xcode/DerivedData  占用了大量空间,这些都是xcode对以前建过的project源码文件建立的索引等,如果不需要可以都删 ...

  5. Uber优步宁波司机注册正式开始啦! UBER宁波司机注册指南!

      自2012年Uber开始向全球进军以来,目前已进入全球56个国家和地区的市场,在全球超过270个城市提供服务, 而Uber公司的估值已高达412亿美元. [目前开通Uber优步叫车服务的中国城市] ...

  6. javaweb学习总结 servlet开发(一)

    转载:http://www.cnblogs.com/xdp-gacl/p/3760336.html 这里主要是将其加入自己的理解过一遍. 这里的代码全在eclipse java ee中执行的. 一.s ...

  7. nodejs授权连接mongodb

    mongodb安装完以后是没有用户连接授权验证的 在控制台直接输入mongo进入交互模式 show dbs use databaseName show collections 这些基本的命令都不会有问 ...

  8. SpringMVC之入门

    Spring MVC简介 Spring MVC:Spring MVC也叫Spring Web MVC,属于表现层框架,是Spring中的一份子. Spring MVC执行流程图 第一个SpringMV ...

  9. 如何开发、调试Hybrid项目-- 入门篇

    前言 随着移动浪潮的兴起,各种APP层出不穷,极速的业务扩展提升了团队对开发效率的要求,这个时候使用IOS&Andriod开发一个APP似乎成本有点过高了,而H5的低成本.高效率.跨平台等特性 ...

  10. html默认属性

    对于display为block来说width默认是满长的,即父级得100%,而高度是0,除非手动设置为100%或指定高度.