mirror of https://github.com/python/cpython.git
Issue 643841: better documentation of the special method lookup process, especially for new-style classes. Also removes the warnings about not being authoritative for new-style classes - the language reference actually covers those fairly well now (albeit in a fashion that isn't always particularly easy to follow).
This commit is contained in:
parent
d868be8805
commit
a510748085
|
@ -742,12 +742,23 @@ Modules
|
|||
of the shared library file.
|
||||
|
||||
Classes
|
||||
Class objects are created by class definitions (see section :ref:`class`). A
|
||||
class has a namespace implemented by a dictionary object. Class attribute
|
||||
references are translated to lookups in this dictionary, e.g., ``C.x`` is
|
||||
translated to ``C.__dict__["x"]``. When the attribute name is not found
|
||||
there, the attribute search continues in the base classes. The search is
|
||||
depth-first, left-to-right in the order of occurrence in the base class list.
|
||||
Both class types (new-style classes) and class objects (old-style/classic
|
||||
classes) are typically created by class definitions (see section
|
||||
:ref:`class`). A class has a namespace implemented by a dictionary object.
|
||||
Class attribute references are translated to lookups in this dictionary, e.g.,
|
||||
``C.x`` is translated to ``C.__dict__["x"]`` (although for new-style classes
|
||||
in particular there are a number of hooks which allow for other means of
|
||||
locating attributes). When the attribute name is not found there, the
|
||||
attribute search continues in the base classes. For old-style classes, the
|
||||
search is depth-first, left-to-right in the order of occurrence in the base
|
||||
class list. New-style classes use the more complex C3 method resolution
|
||||
order which behaves correctly even in the presence of 'diamond'
|
||||
inheritance structures where there are multiple inheritance paths
|
||||
leading back to a common ancestor. Additional details on the C3 MRO used by
|
||||
new-style classes can be found in the documentation accompanying the
|
||||
2.3 release at http://www.python.org/download/releases/2.3/mro/.
|
||||
|
||||
.. XXX: Could we add that MRO doc as an appendix to the language ref?
|
||||
|
||||
.. index::
|
||||
object: class
|
||||
|
@ -768,7 +779,7 @@ Classes
|
|||
static method object, it is transformed into the object wrapped by the static
|
||||
method object. See section :ref:`descriptors` for another way in which
|
||||
attributes retrieved from a class may differ from those actually contained in
|
||||
its :attr:`__dict__`.
|
||||
its :attr:`__dict__` (note that only new-style classes support descriptors).
|
||||
|
||||
.. index:: triple: class; attribute; assignment
|
||||
|
||||
|
@ -1075,7 +1086,7 @@ Internal types
|
|||
New-style and classic classes
|
||||
=============================
|
||||
|
||||
Classes and instances come in two flavors: old-style or classic, and new-style.
|
||||
Classes and instances come in two flavors: old-style (or classic) and new-style.
|
||||
|
||||
Up to Python 2.1, old-style classes were the only flavour available to the user.
|
||||
The concept of (old-style) class is unrelated to the concept of type: if *x* is
|
||||
|
@ -1086,10 +1097,12 @@ a single built-in type, called ``instance``.
|
|||
|
||||
New-style classes were introduced in Python 2.2 to unify classes and types. A
|
||||
new-style class is neither more nor less than a user-defined type. If *x* is an
|
||||
instance of a new-style class, then ``type(x)`` is the same as ``x.__class__``.
|
||||
instance of a new-style class, then ``type(x)`` is typically the same as
|
||||
``x.__class__`` (although this is not guaranteed - a new-style class instance is
|
||||
permitted to override the value returned for ``x.__class__``).
|
||||
|
||||
The major motivation for introducing new-style classes is to provide a unified
|
||||
object model with a full meta-model. It also has a number of immediate
|
||||
object model with a full meta-model. It also has a number of practical
|
||||
benefits, like the ability to subclass most built-in types, or the introduction
|
||||
of "descriptors", which enable computed properties.
|
||||
|
||||
|
@ -1103,16 +1116,18 @@ the way special methods are invoked. Others are "fixes" that could not be
|
|||
implemented before for compatibility concerns, like the method resolution order
|
||||
in case of multiple inheritance.
|
||||
|
||||
This manual is not up-to-date with respect to new-style classes. For now,
|
||||
please see http://www.python.org/doc/newstyle/ for more information.
|
||||
While this manual aims to provide comprehensive coverage of Python's class
|
||||
mechanics, it may still be lacking in some areas when it comes to its coverage
|
||||
of new-style classes. Please see http://www.python.org/doc/newstyle/ for
|
||||
sources of additional information.
|
||||
|
||||
.. index::
|
||||
single: class; new-style
|
||||
single: class; classic
|
||||
single: class; old-style
|
||||
|
||||
The plan is to eventually drop old-style classes, leaving only the semantics of
|
||||
new-style classes. This change will probably only be feasible in Python 3.0.
|
||||
Old-style classes are removed in Python 3.0, leaving only the semantics of
|
||||
new-style classes.
|
||||
|
||||
|
||||
.. _specialnames:
|
||||
|
@ -1129,24 +1144,11 @@ A class can implement certain operations that are invoked by special syntax
|
|||
with special names. This is Python's approach to :dfn:`operator overloading`,
|
||||
allowing classes to define their own behavior with respect to language
|
||||
operators. For instance, if a class defines a method named :meth:`__getitem__`,
|
||||
and ``x`` is an instance of this class, then ``x[i]`` is equivalent [#]_ to
|
||||
``x.__getitem__(i)``. Except where mentioned, attempts to execute an operation
|
||||
raise an exception when no appropriate method is defined.
|
||||
|
||||
For new-style classes, special methods are only guaranteed to work if defined in
|
||||
an object's class, not in the object's instance dictionary. That explains why
|
||||
this won't work::
|
||||
|
||||
>>> class C:
|
||||
... pass
|
||||
...
|
||||
>>> c = C()
|
||||
>>> c.__len__ = lambda: 5
|
||||
>>> len(c)
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: object of type 'C' has no len()
|
||||
|
||||
and ``x`` is an instance of this class, then ``x[i]`` is roughly equivalent
|
||||
to ``x.__getitem__(i)`` for old-style classes and ``type(x).__getitem__(x, i)``
|
||||
for new-style classes. Except where mentioned, attempts to execute an
|
||||
operation raise an exception when no appropriate method is defined (typically
|
||||
:exc:`AttributeError` or :exc:`TypeError`).
|
||||
|
||||
When implementing a class that emulates any built-in type, it is important that
|
||||
the emulation only be implemented to the degree that it makes sense for the
|
||||
|
@ -1479,6 +1481,12 @@ The following methods only apply to new-style classes.
|
|||
method with the same name to access any attributes it needs, for example,
|
||||
``object.__getattribute__(self, name)``.
|
||||
|
||||
.. note::
|
||||
|
||||
This method may still be bypassed when looking up special methods as the
|
||||
result of implicit invocation via language syntax or builtin functions.
|
||||
See :ref:`new-style-special-lookup`.
|
||||
|
||||
|
||||
.. _descriptors:
|
||||
|
||||
|
@ -2274,19 +2282,115 @@ For more information on context managers, see :ref:`typecontextmanager`.
|
|||
The specification, background, and examples for the Python :keyword:`with`
|
||||
statement.
|
||||
|
||||
|
||||
.. _old-style-special-lookup:
|
||||
|
||||
Special method lookup for old-style classes
|
||||
-------------------------------------------
|
||||
|
||||
For old-style classes, special methods are always looked up in exactly the
|
||||
same way as any other method or attribute. This is the case regardless of
|
||||
whether the method is being looked up explicitly as in ``x.__getitem__(i)``
|
||||
or implicitly as in ``x[i]``.
|
||||
|
||||
This behaviour means that special methods may exhibit different behaviour
|
||||
for different instances of a single old-style class if the appropriate
|
||||
special attributes are set differently::
|
||||
|
||||
>>> class C:
|
||||
... pass
|
||||
...
|
||||
>>> c1 = C()
|
||||
>>> c2 = C()
|
||||
>>> c1.__len__ = lambda: 5
|
||||
>>> c2.__len__ = lambda: 9
|
||||
>>> len(c1)
|
||||
5
|
||||
>>> len(c2)
|
||||
9
|
||||
|
||||
|
||||
.. _new-style-special-lookup:
|
||||
|
||||
Special method lookup for new-style classes
|
||||
-------------------------------------------
|
||||
|
||||
For new-style classes, implicit invocations of special methods are only guaranteed
|
||||
to work correctly if defined on an object's type, not in the object's instance
|
||||
dictionary. That behaviour is the reason why the following code raises an
|
||||
exception (unlike the equivalent example with old-style classes)::
|
||||
|
||||
>>> class C(object):
|
||||
... pass
|
||||
...
|
||||
>>> c = C()
|
||||
>>> c.__len__ = lambda: 5
|
||||
>>> len(c)
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: object of type 'C' has no len()
|
||||
|
||||
The rationale behind this behaviour lies with a number of special methods such
|
||||
as :meth:`__hash__` and :meth:`__repr__` that are implemented by all objects,
|
||||
including type objects. If the implicit lookup of these methods used the
|
||||
conventional lookup process, they would fail when invoked on the type object
|
||||
itself::
|
||||
|
||||
>>> 1 .__hash__() == hash(1)
|
||||
True
|
||||
>>> int.__hash__() == hash(int)
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: descriptor '__hash__' of 'int' object needs an argument
|
||||
|
||||
Incorrectly attempting to invoke an unbound method of a class in this way is
|
||||
sometimes referred to as 'metaclass confusion', and is avoided by bypassing
|
||||
the instance when looking up special methods::
|
||||
|
||||
>>> type(1).__hash__(1) == hash(1)
|
||||
True
|
||||
>>> type(int).__hash__(int) == hash(int)
|
||||
True
|
||||
|
||||
In addition to bypassing any instance attributes in the interest of
|
||||
correctness, implicit special method lookup may also bypass the
|
||||
:meth:`__getattribute__` method even of the object's metaclass::
|
||||
|
||||
>>> class Meta(type):
|
||||
... def __getattribute__(*args):
|
||||
... print "Metaclass getattribute invoked"
|
||||
... return type.__getattribute__(*args)
|
||||
...
|
||||
>>> class C(object):
|
||||
... __metaclass__ = Meta
|
||||
... def __len__(self):
|
||||
... return 10
|
||||
... def __getattribute__(*args):
|
||||
... print "Class getattribute invoked"
|
||||
... return object.__getattribute__(*args)
|
||||
...
|
||||
>>> c = C()
|
||||
>>> c.__len__() # Explicit lookup via instance
|
||||
Class getattribute invoked
|
||||
10
|
||||
>>> type(c).__len__(c) # Explicit lookup via type
|
||||
Metaclass getattribute invoked
|
||||
10
|
||||
>>> len(c) # Implicit lookup
|
||||
10
|
||||
|
||||
Bypassing the :meth:`__getattribute__` machinery in this fashion
|
||||
provides significant scope for speed optimisations within the
|
||||
interpreter, at the cost of some flexibility in the handling of
|
||||
special methods (the special method *must* be set on the class
|
||||
object itself in order to be consistently invoked by the interpreter).
|
||||
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#] Since Python 2.2, a gradual merging of types and classes has been started that
|
||||
makes this and a few other assertions made in this manual not 100% accurate and
|
||||
complete: for example, it *is* now possible in some cases to change an object's
|
||||
type, under certain controlled conditions. Until this manual undergoes
|
||||
extensive revision, it must now be taken as authoritative only regarding
|
||||
"classic classes", that are still the default, for compatibility purposes, in
|
||||
Python 2.2 and 2.3. For more information, see
|
||||
http://www.python.org/doc/newstyle/.
|
||||
|
||||
.. [#] This, and other statements, are only roughly true for instances of new-style
|
||||
classes.
|
||||
.. [#] It *is* possible in some cases to change an object's type, under certain
|
||||
controlled conditions. It generally isn't a good idea though, since it can
|
||||
lead to some very strange behaviour if it is handled incorrectly.
|
||||
|
||||
.. [#] A descriptor can define any combination of :meth:`__get__`,
|
||||
:meth:`__set__` and :meth:`__delete__`. If it does not define :meth:`__get__`,
|
||||
|
|
Loading…
Reference in New Issue