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$
Last-Modified: $Date
Author: Alex Gaynor <alex.gaynor@gmail.com>
Status: Draft
Status: Accepted
Type: Standards Track
Content-Type: text/x-rst
Created: 14-July-2012
@ -13,18 +13,19 @@ Post-History: http://mail.python.org/pipermail/python-dev/2012-July/120920.html
Abstract
========
CPython currently defines an ``__length_hint__`` method on several types, such
as various iterators. This method is then used by various other functions (such
as ``list``) to presize lists based on the estimated returned by
``__length_hint__``. Types can then define ``__length_hint__`` which are not
sized, and thus should not define ``__len__``, but can estimate or compute a
size (such as many iterators).
CPython currently defines a ``__length_hint__`` method on several
types, such as various iterators. This method is then used by various
other functions (such as ``list``) to presize lists based on the
estimate returned by ``__length_hint__``. Types which are not sized,
and thus should not define ``__len__``, can then define
``__length_hint__``, to allow estimating or computing a size (such as
many iterators).
Proposal
========
Specification
=============
This PEP proposes formally documenting ``__length_hint__`` for other
interpreter and non-standard library Python to implement.
This PEP formally documents ``__length_hint__`` for other
interpreters and non-standard-library Python modules to implement.
``__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
@ -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
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
follow semantics (which define how ``__length_hint__`` should be used::
In addition, a new function ``operator.length_hint`` hint is added,
with the follow semantics (which define how ``__length_hint__`` should
be used)::
def length_hint(obj, default):
"""
Return an estimate of the number of items in obj. This is
useful for presizing containers when building from an iterable.
def length_hint(obj, default=0):
"""Return an estimate of the number of items in obj.
If the object supports len(), the result will be exact. Otherwise, it
may over or underestimate by an arbitrary amount. The result will be an
integer >= 0.
This is useful for presizing containers when building from an
iterable.
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)
except TypeError:
else:
try:
get_hint = obj.__length_hint__
except AttributeError:
@ -55,13 +58,18 @@ follow semantics (which define how ``__length_hint__`` should be used::
if hint is NotImplemented:
return default
if not isinstance(hint, int):
raise TypeError("Length hint must be an integer, not %r" % type(hint))
if hint < 0:
raise ValueError("Length hint (%r) must be >= 0" % hint)
return hint
raise TypeError("Length hint must be an integer, not %r" %
type(hint))
return max(hint, 0)
Callers are required to provide a default value, because there is no sane
return value for objects which do not provide a length or length hint.
Note: there is no good way to spell "obj has a __len__ method" in pure
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