Skip to content

Commit

Permalink
Merge branch 'master' of github.com:iceout/PyZh
Browse files Browse the repository at this point in the history
Conflicts:
	docs/Descriptor-HOW-TO-Guide.rst
  • Loading branch information
Zhang Xuanyi committed Nov 26, 2014
2 parents b44962d + 7105274 commit c30eff6
Showing 1 changed file with 10 additions and 8 deletions.
18 changes: 10 additions & 8 deletions docs/Descriptor-HOW-TO-Guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Python描述器引导(翻译)

:联系: <python at rcn dot com>

:翻译: hit9
:翻译: hit9, iceout

:译者注: 原文链接- http://docs.python.org/2/howto/descriptor.html

Expand All @@ -26,7 +26,7 @@ Python描述器引导(翻译)

一般来说,一个描述器是一个有“绑定行为”的对象属性,它的访问控制被描述器协定方法重写。这些方法是 :meth:`__get__`, :meth:`__set__`, 和 :meth:`__delete__`.有这些方法的对象叫做描述器。

默认对属性的访问控制是从对象的字典里面(__dict__)中获取(get), 设置(set)和删除(delete)它.对于实例 ``a`` 来说, ``a.x`` 的查找顺序是, ``a.__dict__['x']`` , 然后 ``type(a).__dict__['x']`` , 然后找 ``type(a)`` 的父类(不包括元类(metaclass)).如果查找到的值是一个描述器, Python就会调用描述器的方法来重写默认的控制行为。这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。注意, 只有在新式对象或新式类中时描述器才会起作用。(新式类是继承自 ``type`` 或者 ``object`` 的类)
默认对属性的访问控制是从对象的字典里面(__dict__)中获取(get), 设置(set)和删除(delete)它.对于实例 ``a`` 来说, ``a.x`` 的查找顺序是, ``a.__dict__['x']`` , 然后 ``type(a).__dict__['x']`` , 然后找 ``type(a)`` 的父类(不包括元类(metaclass)).如果查找到的值是一个描述器, Python就会调用描述器的方法来重写默认的控制行为。这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。注意, 只有在新式类中时描述器才会起作用。(新式类是继承自 ``type`` 或者 ``object`` 的类)

描述器是强大的,应用广泛的。描述器正是属性, 实例方法, 静态方法, 类方法和 ``super`` 的背后的实现机制。描述器在Python自身中广泛使用,以实现Python 2.2中引入的新式类。描述器简化了底层的C代码,并为Python的日常编程提供了一套灵活的新工具。

Expand All @@ -52,11 +52,13 @@ Python描述器引导(翻译)

描述器可以直接这么调用: ``d.__get__(obj)``

然而更多的时候描述器用来拦截对实例属性的访问。举例来说, ``obj.d`` 会在 ``obj`` 的字典中找 ``d`` ,如果 ``d`` 定义了 ``__get__`` 方法,那么 ``d.__get__(obj)`` 会被调用
然而更常见的情况是描述器在属性访问时被自动调用。举例来说, ``obj.d`` 会在 ``obj`` 的字典中找 ``d`` ,如果 ``d`` 定义了 ``__get__`` 方法,那么 ``d.__get__(obj)`` 会依据下面的优先规则被调用

调用的细节取决于 ``obj`` 是一个类还是一个实例。另外,描述器只在它的类是个新式类的时候起作用。继承于 ``object`` 的类叫做新式类。
调用的细节取决于 ``obj`` 是一个类还是一个实例。另外,描述器只对于新式对象和新式类才起作用。继承于 ``object`` 的类叫做新式类。

对于对象来讲,方法 :meth:`type.__getattribute__` 把 ``B.x`` 变成 ``B.__dict__['x'].__get__(None, B)`` 。用Python来描述就是::
对于对象来讲,方法 :meth:`object.__getattribute__` 把 ``b.x`` 变成 ``type(b).__dict__['x'].__get__(b, type(b))`` 。具体实现是依据这样的优先顺序:资料描述器优先于实例变量,实例变量优先于非资料描述器,__getattr__()方法(如果对象中包含的话)具有最低的优先级。完整的C语言实现可以在 `Objects/object.c <https://hg.python.org/cpython/file/2.7/Objects/object.c>`_ 中 `PyObject_GenericGetAttr() <https://docs.python.org/2/c-api/object.html#c.PyObject_GenericGetAttr>`_ 查看。

对于类来讲,方法 :meth:`type.__getattribute__` 把 ``B.x`` 变成 ``B.__dict__['x'].__get__(None, B)`` 。用Python来描述就是::

def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
Expand All @@ -74,16 +76,16 @@ Python描述器引导(翻译)
* 资料描述器总是比实例字典优先。
* 非资料描述器可能被实例字典重写。(非资料描述器不如实例字典优先)

``super()`` 返回的对象同样有用来调用描述器的 :meth:`__getattribute__` 方法。调用 ``super(B, obj).m()`` 时会去在 ``obj.__class__.__mro__`` 中查找B的父类,然后返回 ``A.__dict__['m'].__get__(obj, A)`` 。如果没有描述器, 原样返回 ``m`` 。如果连实例字典中都找不到 ``m`` ,继续调用 :meth:`object.__getattribute__`.
``super()`` 返回的对象同样有一个定制的 :meth:`__getattribute__` 方法用来调用描述器。调用 ``super(B, obj).m()`` 时会先在 ``obj.__class__.__mro__`` 中查找与B紧邻的基类A,然后返回 ``A.__dict__['m'].__get__(obj, A)`` 。如果不是描述器,原样返回 ``m`` 。如果实例字典中找不到 ``m`` ,会回溯继续调用 :meth:`object.__getattribute__` 查找。(译者注:即在 ``__mro__`` 中的下一个基类中查找)

注意:在Python 2.2中,如果 ``m`` 是一个描述器, ``super(B, obj).m()`` 只会调用方法 :meth:`__get__` 。在Python 2.3中,非资料描述器(除非是个旧式类)也会被调用。 :c:func:`super_getattro()` 的实现细节在:
`Objects/typeobject.c <http://svn.python.org/view/python/trunk/Objects/typeobject.c?view=markup>`_
,一个等价的Python实现在 `Guido's Tutorial`_.
[del] 一个等价的Python实现在 `Guido's Tutorial`_ [/del] (译者注:原文此句已删除,保留供大家参考)。

.. _`Guido's Tutorial`: http://www.python.org/2.2.3/descrintro.html#cooperation


以上展示了描述器的机理是在 :class:`object`, :class:`type`, 和 :func:`super` 的 :meth:`__getattribute__()` 方法中实现的。由 :class:`object` 派生出的类自动的继承这个机理,或者它们有个有类似机理的元类。同样,可以重写类的 :meth:`__getattribute__()` 方法来关闭这个类的描述器行为。
以上展示了描述器的机理是在 :class:`object`, :class:`type`, 和 :class:`super` 的 :meth:`__getattribute__()` 方法中实现的。由 :class:`object` 派生出的类自动的继承这个机理,或者它们有个有类似机理的元类。同样,可以重写类的 :meth:`__getattribute__()` 方法来关闭这个类的描述器行为。

描述器例子
----------
Expand Down

0 comments on commit c30eff6

Please sign in to comment.