Improve and accept PEP 424 (__length_hint__).

This commit is contained in:
Guido van Rossum 2012-07-30 10:12:18 -07:00
parent 9962846ad1
commit 03909e4c50
1 changed files with 36 additions and 28 deletions

View File

@ -3,7 +3,7 @@ Title: A method for exposing a length hint
Version: $Revision$ Version: $Revision$
Last-Modified: $Date Last-Modified: $Date
Author: Alex Gaynor <alex.gaynor@gmail.com> Author: Alex Gaynor <alex.gaynor@gmail.com>
Status: Draft Status: Accepted
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst Content-Type: text/x-rst
Created: 14-July-2012 Created: 14-July-2012
@ -13,18 +13,19 @@ Post-History: http://mail.python.org/pipermail/python-dev/2012-July/120920.html
Abstract Abstract
======== ========
CPython currently defines an ``__length_hint__`` method on several types, such CPython currently defines a ``__length_hint__`` method on several
as various iterators. This method is then used by various other functions (such types, such as various iterators. This method is then used by various
as ``list``) to presize lists based on the estimated returned by other functions (such as ``list``) to presize lists based on the
``__length_hint__``. Types can then define ``__length_hint__`` which are not estimate returned by ``__length_hint__``. Types which are not sized,
sized, and thus should not define ``__len__``, but can estimate or compute a and thus should not define ``__len__``, can then define
size (such as many iterators). ``__length_hint__``, to allow estimating or computing a size (such as
many iterators).
Proposal Specification
======== =============
This PEP proposes formally documenting ``__length_hint__`` for other This PEP formally documents ``__length_hint__`` for other
interpreter and non-standard library Python to implement. interpreters and non-standard-library Python modules to implement.
``__length_hint__`` must return an integer (else a TypeError is raised) or ``__length_hint__`` must return an integer (else a TypeError is raised) or
``NotImplemented, and is not required to be accurate. It may return a value ``NotImplemented, and is not required to be accurate. It may return a value
@ -32,21 +33,23 @@ that is either larger or smaller than the actual size of the container. A
return value of ``NotImplemented`` indicates that there is no finite length return value of ``NotImplemented`` indicates that there is no finite length
estimate. It may not return a negative value (else a ValueError is raised). estimate. It may not return a negative value (else a ValueError is raised).
In addition, a new function ``operator.length`` hint is added, having the In addition, a new function ``operator.length_hint`` hint is added,
follow semantics (which define how ``__length_hint__`` should be used:: with the follow semantics (which define how ``__length_hint__`` should
be used)::
def length_hint(obj, default): def length_hint(obj, default=0):
""" """Return an estimate of the number of items in obj.
Return an estimate of the number of items in obj. This is
useful for presizing containers when building from an iterable.
If the object supports len(), the result will be exact. Otherwise, it This is useful for presizing containers when building from an
may over or underestimate by an arbitrary amount. The result will be an iterable.
integer >= 0.
If the object supports len(), the result will be
exact. Otherwise, it may over- or under-estimate by an
arbitrary amount. The result will be an integer >= 0.
""" """
try: if <obj has a __len__ method>:
return len(obj) return len(obj)
except TypeError: else:
try: try:
get_hint = obj.__length_hint__ get_hint = obj.__length_hint__
except AttributeError: except AttributeError:
@ -55,13 +58,18 @@ follow semantics (which define how ``__length_hint__`` should be used::
if hint is NotImplemented: if hint is NotImplemented:
return default return default
if not isinstance(hint, int): if not isinstance(hint, int):
raise TypeError("Length hint must be an integer, not %r" % type(hint)) raise TypeError("Length hint must be an integer, not %r" %
if hint < 0: type(hint))
raise ValueError("Length hint (%r) must be >= 0" % hint) return max(hint, 0)
return hint
Callers are required to provide a default value, because there is no sane Note: there is no good way to spell "obj has a __len__ method" in pure
return value for objects which do not provide a length or length hint. Python. In CPython, this comes down to checking for a ``sq_length``
slot. Other implementations presumably have their own way of
checking. Calling ``len(obj)`` and catching TypeError is not quite
correct (as it would assume no __len__ method exists when in fact one
exists but calling it raises TypeError); checking ``hasattr(obj,
'__len__')`` likewise is incorrect if obj is a class defining a
``__len__`` method for its instances.
Rationale Rationale