描述符简介

请给作者点赞-->原文链接

简介

Python 描述符是一种创建托管属性的方法。除了其他优点外,托管属性还用于保护属性不受修改,或自动更新某个依赖属性的值。

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

描述符协议

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

  • set
  • get
  • delete

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

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

清单 1. 描述符方法

1

2

3

__get__(self, instance, owner)

__set__(self, instance, value)

__delete__(self, instance)

其中:

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

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

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

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

需要使用描述符的情况

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

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

创建描述符

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

  • 创建一个类并覆盖任意一个描述符方法:__set____ get__ 和 __delete__。当需要某个描述符跨多个不同的类和属性,例如类型验证,则使用该方法。
  • 使用属性类型,这种方法可以更加简单、灵活地创建描述符。
  • 使用属性描述符,它结合了属性类型方法和 Python 描述符。

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

使用类方法创建描述符

清单 2 演示在 Python 中控制属性分配非常简单。

清单 2. 使用类方法创建描述符

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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()

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


1

2

3

4

5

6

7

8

>>> 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

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

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

使用属性类型创建描述符

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

  • fget:属性获取方法
  • fset:属性设置方法
  • fdel:属性删除方法
  • doc:docstring

使用属性重写该例子,如 清单 3 所示。

清单 3. 使用属性类型创建描述符

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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.")

使用该代码并查看输出:


1

2

3

4

5

6

7

8

>>> user = Person()

>>> user.name = ‘john smith‘

Setting: john smith

>>> user.name

Getting: John Smith

‘John Smith‘

>>> del user.name

Deleting: John Smith

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

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


1

2

name = property(fget, None, fdel, "I‘m the property")

user.name = ‘john smith‘

输出为:


1

2

3

4

Traceback (most recent call last):

File stdin, line 21, in mоdule

user.name = ‘john smith‘

AttributeError: can‘t set attribute

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

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

清单 4. 使用属性修饰符创建描述符

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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 属性。该解决方案使用属性类型构建数据描述符。

清单 5. 在运行时创建描述符

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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)

让我们运行这段代码:


1

2

3

4

5

6

7

8

9

10

11

12

>>> 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 描述符可以利用新的样式类实现强大而灵活的属性管理。通过结合使用描述符,可以实现优雅的编程,允许创建 Setters 和 Getters 以及只读属性。它还允许您根据值或类型请求进行属性验证。您可以在许多不同的领域应用描述符,但是使用时需保持谨慎的态度,避免由于覆盖普通对象行为而产生不必要的代码复杂性。

原文地址:https://www.cnblogs.com/amou/p/9231697.html

时间: 2024-08-29 05:09:57

描述符简介的相关文章

USB HID报告及报告描述符简介

在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等.USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符.        USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告.输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等:输出报告是主机发送给USB设备的,例如键盘上的数字

转 关于USB HID报告描述符

原文地址 USB HID报告及报告描述符简介 在USB中,USBHOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等.USB报 告描述符(ReportDescriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符.USBHID设备是通过报告来给传送数据的,报告 有输入报告和输出报告.输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等:输出 报告是主机发送在

USB HID描述符【转】

本文转载自: USB是个通用的总线,端口都是统一的.但是USB设备却各种各样,例如USB鼠标,USB键盘,U盘等等,那么USB主机是如何识别出不同的设备的呢?这就要依赖于描述符了.USB的描述符主要有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,HID描述符,报告描述符等等.关于报告描述符,请看我以前写的:<USB HID报告及报告描述符简介 > http://group.ednchina.com/93/198.aspx.一个USB设备有一个设备描述符,设备描述符里面决定了该设

文件描述符与重定向

文件描述符简介:文件描述符在形式上是一个非负整数,每一个文件描述符会与一个打开文件相对应,内核利用文件描述符来访问文件,最广为人知的文件描述符有stdin(标准输入),stdout(标准输出),stderr(标准错误),系统分别事先为它们保留了三个文件描述符0,1,2,我们也可以通过特殊命令给我们的的文件指定文件描述符. 重定向的意思:Linux中,IO重定向是将某一个文件描述符的内容转移到另一个指定的文件描述符中,通常与文件描述符有关. 最常用的我们可以将标准输出的内容重定向到指定文件中.通过

转载python描述符介绍

来源:http://www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 简介 Python 2.2 引进了 Python 描述符,同时还引进了一些新的样式类,但是它们并没有得到广泛使用.Python 描述符是一种创建托管属性的方法.除了其他优点外,托管属性还用于保护属性不受修改,或自动更新某个依赖属性的值. 描述符增加了对 Python 的理解,改善了编码技能.本文介绍了描述符协议,并演示了如何创建和使用描述符. 描述符协

python Descriptor (描述符)

简介: python 描述符是新式类(继承自object)中的语言协议,基于描述符可以提供更佳优雅的解决方案. python的classmethod, staticmethod, property都是基于描述符建立的. 描述符的协议: 定义了__set__, __get__, __delete__3个方法中任何一个方法的object可以作为描述符. 描述符分类: 同时定义了__set__,__get__被叫做data descriptor. 只定义了__get__被叫做no-data descr

保护模式_1_段寄存器_段描述符_段选择子

1 段寄存器 1-1 段寄存器的结构 图示: 结构体表示: struct SegMent { WORD Selector; WORD Attribute; DWORD Base; DWORD Limit; } 1-2 段寄存器的属性探测 可以通过MOV指令进行读写(LDTR和TR除外) 段寄存器成员简介 探测Attribute是否存在 int var=0; int main() { __asm { mov ax, ss //cs不行 cs是可读 可执行 但不可写 mov ds, ax mov d

OpenCV4Android 提取特征点描述符(Feature Descriptor)

OpenCV4Android 提取特征点描述符(Feature Descriptor) 在得到keypoints之后(参考前面),通过使用相应的FeatureDescriptor就可计算得到关键点处的描述子. Native Code: JNIEXPORT void JNICALL Java_com_example_test_NativeUtil_computeDescripors( JNIEnv *env, jclass thiz, jlong mGrayAddr, jlong mRgbaAdd

USB 描述符

标准的USB设备有5种USB描述符:设备描述符,配置描述符,字符串描述符,接口描述符,端点描述符. 1 // Standard Device Descriptor 2 typedef struct 3 { 4 u8 bLength; 5 u8 bDescriptorType; 6 u16 bcdUSB; 7 u8 bDeviceClass; 8 u8 bDeviceSubClass; 9 u8 bDeviceProtocol; 10 u8 bMaxPacketSize0; 11 u16 idVe