来源: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. Spearman秩相关系数和Pearson皮尔森相关系数

    1.Pearson皮尔森相关系数 皮尔森相关系数也叫皮尔森积差相关系数,用来反映两个变量之间相似程度的统计量.或者说用来表示两个向量的相似度. 皮尔森相关系数计算公式如下:

  2. 有关attribute和property,以及各自对select中option的影响

    这个问题老生常谈,但是直到现在我依旧时常会把它搞混.下面列一些各自的特性.   attribute property 设置方法 option.setAttribute('selected', true ...

  3. Enable rsh on MAC OS with command line

    1. Enable rsh on macos. 1). os version (10.0) Enabling the "Allow remote login" option tur ...

  4. 1st贝塞尔函数的使用

    x=-100:0.1:100; y1=besselj(7,x);y2=besselj(10,x);y3=besselj(20,x);y4=besselj(40,x);y5=besselj(60,x); ...

  5. Excel常用操作

    [对Excel工作表,按某一列数据进行排序] 选中这些数据,在菜单栏上点"数据 - 排序",在弹出的窗口中的主要关键字里选择这一列,按升序或降序,那么其它的数据也会跟着它一一对应变 ...

  6. MySQL设置字符集为UTF8(Windows版)

    Windows版MySQL设置字符集全部为utf8的方式 MySQL安装目录下的my.ini文件 [client]节点 default-character-set=utf8    (增加) [mysq ...

  7. BeautifulSoup-find,findAll

    BeautifulSoup的主要函数使用 from bs4 import BeautifulSouphtml = """<html><head>& ...

  8. HTTP 响应头信息

    HTTP 响应头信息 HTTP请求头提供了关于请求,响应或者其他的发送实体的信息. 在本章节中我们将具体来介绍HTTP响应头信息.

  9. mac中使用brew安装软件,下载太慢怎么办?

    mac中使用brew安装软件,下载太慢怎么办? 本文所说的软件是指较大的软件,如果软件较小,例如软件只有几M,那么使用此方法后,提升会非常小. 了解brew原理: 1: 从网络下载安装包 2: 执行一 ...

  10. JDBC的作用及重要接口

    JDBC是由一系列连接(Connection).SQL语句(Statement)和结果集(ResultSet)构成的,其主要作用概括起来有如下3个方面:    建立与数据库的连接.    向数据库发起 ...