def next(iterable[, default]):
    """
    Returns:
        Return the next item from the iterator.
    Raises:
        StopIteration: when iterator is empty and default is not specified
    """

def first(iterable, default=None):
    """
    Returns:
        default (which defaults to None) if the iterator is empty
        or the first item of the iterable
    Raises:
        StopIteration: when iterator is empty and default is not specified
    """

If this is the distinction, I'm now -1 on adding .first() at all due to
the likelihood that I, being an idiot, will do:

    iterables = [[None, 2, 3], []]
    for it in iterables:
        x = first(it)
        if x is not None:
            print(x)

And that's not a risk I'm willing to take. IMHO, a
StopIteration / ValueError / TooFewItems(ValueError)
exception is preferable in most cases.

more_itertools.more.first questions the reasoning behind
catching StopIteration and raising ValueError instead.


_default = object()
def first(iterable, default=_default):
    """
    Returns:
        the first item of iterable or default if iterable raises StopIteration
        and default is specified.
    Raises:
        StopIteration: when iterator is empty and default is not specified
        ValueError: when iterator is empty and default is not specified
        TooFewItems: when iterator is empty and default is not specified

    .. note:: :func:`next` accepts a default value as a second argument.
        :func:`next` raises StopIteration.

    """

For a .one(iterable, default=_default) function, it makes sense to have
TooFewItems and TooManyItems Exceptions that subclass ValueError because
the alternative (calling next again and determining whether it's the
first or the second call to next() that's raising StopIteration) is
verbose.  Does this justify new builtin Exceptions? If so,
.first() should raise TooFewItems(ValueError) as well.

https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.one


If we're looking to add list.get(n, default=None) that would seem to be
a different argument.

...

s = set('abc')
assert s == {'a','b','c'}

# This fails approximately 1/3 of the time
assert next(iter(s)) == 'a'
# This fails approximately 1/3 of the time
assert [x for x in s][0] == 'a'
# This fails approximately 1/3 of the time
assert list(s)[0] == tuple(s)[0] == 'a'
# This'll also fail approximately 1/3 of the time;
# this is not obvious to most non-core developers.
assert first(s) == 'a'

Sets are not collections.abc.Sequence because they do not implement __getitem__.
Are there other unordered Iterables in the standard library
that the .first() docstring could mention after mentioning 2-arg next()?

On Tue, Dec 10, 2019 at 12:44 AM Tim Peters <tim.pet...@gmail.com> wrote:
>
> [Guido]
> > The argument that first(it) and next(it) "look the same" doesn't convince
> > me;
>
> I'm sorry - I guess then I have absolutely no idea what you were
> trying to say, and read it completely wrong.
>
> > if these look the same then all function applications look the same, and
> > that can certainly not have been Meertens' intention.
>
> No argument on that from me ;-)
>
> > But if everyone thinks that first() should raise, fine, this thread is way 
> > too long
> > already (I should have kept it muted :-).
>
> It was being discussed.  The 1-argument more-itertools `first()` does
> raise on an exhausted iterator, and that does make most sense to me.
> In my algorithms I usually "know" I'm not trying to take an element
> from an empty iterable, and have no use for a default value in such a
> case.  Since there's no non-destructive way to assert that the
> iterable is not exhausted, raising an exception if it is exhausted is
> most useful.
>
>     _empty = object()
>     a = first(iterable, _empty)
>     if a is _empty:
>         raise ...
>
> is a PITA by comparison, as is my _current_ idiom:
>
>     for a in iterable:
>         break
>     else:
>         raise ...

Is this pattern in the tutorial?

>
> Plain old
>
>     a = first(iterable)
>
> would be perfect - but only if it raised.

+1. How is this distinct from:

    first = next
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/YOBTRLFSACYEA3QZQAX3LW2ZGTGCPS36/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to