[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread Guido van Rossum
Shouldn’t this go to itertools-ideas? :-)

On Mon, Jul 27, 2020 at 13:56 David Mertz  wrote:

> I don't like consuming the iterator in the exception case. You might
> expect just one, but have a fallback approach for more. You could build the
> safer behavior using itertools.tee() or itertools.chain().
>
> On Mon, Jul 27, 2020, 3:10 PM Noam Yorav-Raphael 
> wrote:
>
>> Hi,
>>
>> There's a simple function that I use many times, and I think may be a
>> good fit to be added to itertools. A function that gets an iterator, and if
>> it has exactly one element returns it, and otherwise raises an exception.
>> This is very useful for cases where I do some sort of query that I expect
>> to get exactly one result, and I want an exception to be raised if I'm
>> wrong. For example:
>>
>> jack = one(p for p in people if p.id == '1234')
>>
>> sqlalchemy already has such a function for queries:
>> https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one
>>
>> This is my implementation:
>>
>> def one(iterable):
>> it = iter(iterable)
>> try:
>> r = next(it)
>> except StopIteration:
>> raise ValueError("Iterator is empty")
>> try:
>> next(it)
>> except StopIteration:
>> return r
>> else:
>> raise ValueError("Iterator has more than one item")
>>
>> What do you think?
>>
>> Thanks,
>> Noam
>> ___
>> Python-Dev mailing list -- python-dev@python.org
>> To unsubscribe send an email to python-dev-le...@python.org
>> https://mail.python.org/mailman3/lists/python-dev.python.org/
>> Message archived at
>> https://mail.python.org/archives/list/python-dev@python.org/message/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/N75BG5XVXKENVWAPU4K5UP4I3DKXTITO/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/IMED3FXEGFYJJX7KCWQLYO7SPNJAO2MS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread David Mertz
I don't like consuming the iterator in the exception case. You might expect
just one, but have a fallback approach for more. You could build the safer
behavior using itertools.tee() or itertools.chain().

On Mon, Jul 27, 2020, 3:10 PM Noam Yorav-Raphael  wrote:

> Hi,
>
> There's a simple function that I use many times, and I think may be a good
> fit to be added to itertools. A function that gets an iterator, and if it
> has exactly one element returns it, and otherwise raises an exception. This
> is very useful for cases where I do some sort of query that I expect to get
> exactly one result, and I want an exception to be raised if I'm wrong. For
> example:
>
> jack = one(p for p in people if p.id == '1234')
>
> sqlalchemy already has such a function for queries:
> https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one
>
> This is my implementation:
>
> def one(iterable):
> it = iter(iterable)
> try:
> r = next(it)
> except StopIteration:
> raise ValueError("Iterator is empty")
> try:
> next(it)
> except StopIteration:
> return r
> else:
> raise ValueError("Iterator has more than one item")
>
> What do you think?
>
> Thanks,
> Noam
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/N75BG5XVXKENVWAPU4K5UP4I3DKXTITO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread Noam Yorav-Raphael
Thanks for the suggestion! I agree that using a list is clearer that having
a trailing comma, I like it!

I still think that having a one() function would be useful, since:
1. I think it spells the intention more clearly. Also the exception would
be easier to understand, since errors in tuple unpacking usually mean
something else.
2. The one() function allows you to use the result inside an expression
without assigning it to a variable.

Cheers,
Noam

On Mon, Jul 27, 2020 at 10:30 PM Chris Angelico  wrote:

> On Tue, Jul 28, 2020 at 5:24 AM Steven Barker  wrote:
> >
> > A single-name unpacking assignment can do exactly what you want, albeit
> with slightly less helpful exception messages:
> >
> > jack, = (p for p in people if p.id == '1234') # note comma after
> the name jack
> >
>
> Agreed. As a minor readability refinement, I would prefer to spell
> this with square brackets:
>
> [jack] = (p for p in people if p.id == '1234')
>
> The effect is identical, but for the one-item unpack, I prefer not to
> have the vital-but-subtle trailing comma.
>
> (You can use square brackets on larger assignment lists too, but they
> don't add anything.)
>
> ChrisA
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/62ZAKSHT6VHT66CHFBPJHHAUQSW2S3DK/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/LHJZWOE7S4TQDZ5FTEN3GKK2Y3J6WFH3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread Paul Ganssle
I would think that you can use tuple unpacking for this?

    single_element, = some_iterator

Will attempt to unpack the some_iterator into single_element and fail if
single_element doesn't have exactly 1 element. It also has the added
benefit that it works for any number of elements:

one, two = some_iterator

Example:

>>> a = [1]
>>> one, = a
>>> one
1
>>> b = [1, 2]
>>> one, = b
---
ValueError    Traceback (most recent call last)
 in 
> 1 one, = b

ValueError: too many values to unpack (expected 1)
>>> c = []
>>> one, = c
---
ValueError    Traceback (most recent call last)
 in 
> 1 one, = c

ValueError: not enough values to unpack (expected 1, got 0)

Best,
Paul

On 7/27/20 3:19 PM, Rollo Konig-Brock wrote:
> I second this as being useful.
>
> However the “pythonic” way (whatever that means nowadays) is to do a
> for break else loop, which I think is kinda difficult to read as you
> need to make a few assumptions.
>
> Rollo
>
>> On 27 Jul 2020, at 20:06, Noam Yorav-Raphael  wrote:
>>
>> 
>> Hi,
>>
>> There's a simple function that I use many times, and I think may be a
>> good fit to be added to itertools. A function that gets an iterator,
>> and if it has exactly one element returns it, and otherwise raises an
>> exception. This is very useful for cases where I do some sort of
>> query that I expect to get exactly one result, and I want an
>> exception to be raised if I'm wrong. For example:
>>
>> jack = one(p for p in people if p.id  == '1234')
>>
>> sqlalchemy already has such a function for
>> queries: 
>> https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one
>>
>> This is my implementation:
>>
>> def one(iterable):
>>     it = iter(iterable)
>>     try:
>>         r = next(it)
>>     except StopIteration:
>>         raise ValueError("Iterator is empty")
>>     try:
>>         next(it)
>>     except StopIteration:
>>         return r
>>     else:
>>         raise ValueError("Iterator has more than one item")
>>
>> What do you think?
>>
>> Thanks,
>> Noam
>> ___
>> Python-Dev mailing list -- python-dev@python.org
>> To unsubscribe send an email to python-dev-le...@python.org
>> https://mail.python.org/mailman3/lists/python-dev.python.org/
>> Message archived at
>> https://mail.python.org/archives/list/python-dev@python.org/message/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/3NA4E3QCTSLGIQXAMVWUL66TK6O7ZHLS/
> Code of Conduct: http://python.org/psf/codeofconduct/


signature.asc
Description: OpenPGP digital signature
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ZLCCVBRXWAUDYQ3K42QOMLDERWMZMHI2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread Chris Angelico
On Tue, Jul 28, 2020 at 5:24 AM Steven Barker  wrote:
>
> A single-name unpacking assignment can do exactly what you want, albeit with 
> slightly less helpful exception messages:
>
> jack, = (p for p in people if p.id == '1234') # note comma after the name 
> jack
>

Agreed. As a minor readability refinement, I would prefer to spell
this with square brackets:

[jack] = (p for p in people if p.id == '1234')

The effect is identical, but for the one-item unpack, I prefer not to
have the vital-but-subtle trailing comma.

(You can use square brackets on larger assignment lists too, but they
don't add anything.)

ChrisA
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/62ZAKSHT6VHT66CHFBPJHHAUQSW2S3DK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread Steven Barker
A single-name unpacking assignment can do exactly what you want, albeit
with slightly less helpful exception messages:

jack, = (p for p in people if p.id == '1234') # note comma after the
name jack

If no value is yielded by the generator expression, you'll get "ValueError:
not enough values to unpack (expected 1, got 0)". If multiple values are
yielded, you'll instead get "ValueError: too many values to unpack
(expected 1)".
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/Y6HFE3HIPX67UCFSLO6WMH4CKVAEJYJO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Function suggestion: itertools.one()

2020-07-27 Thread Rollo Konig-Brock
I second this as being useful.

However the “pythonic” way (whatever that means nowadays) is to do a for break 
else loop, which I think is kinda difficult to read as you need to make a few 
assumptions.

Rollo

> On 27 Jul 2020, at 20:06, Noam Yorav-Raphael  wrote:
> 
> 
> Hi,
> 
> There's a simple function that I use many times, and I think may be a good 
> fit to be added to itertools. A function that gets an iterator, and if it has 
> exactly one element returns it, and otherwise raises an exception. This is 
> very useful for cases where I do some sort of query that I expect to get 
> exactly one result, and I want an exception to be raised if I'm wrong. For 
> example:
> 
> jack = one(p for p in people if p.id == '1234')
> 
> sqlalchemy already has such a function for queries: 
> https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one
> 
> This is my implementation:
> 
> def one(iterable):
> it = iter(iterable)
> try:
> r = next(it)
> except StopIteration:
> raise ValueError("Iterator is empty")
> try:
> next(it)
> except StopIteration:
> return r
> else:
> raise ValueError("Iterator has more than one item")
> 
> What do you think?
> 
> Thanks,
> Noam
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/
> Code of Conduct: http://python.org/psf/codeofconduct/
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/3NA4E3QCTSLGIQXAMVWUL66TK6O7ZHLS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Function suggestion: itertools.one()

2020-07-27 Thread Noam Yorav-Raphael
Hi,

There's a simple function that I use many times, and I think may be a good
fit to be added to itertools. A function that gets an iterator, and if it
has exactly one element returns it, and otherwise raises an exception. This
is very useful for cases where I do some sort of query that I expect to get
exactly one result, and I want an exception to be raised if I'm wrong. For
example:

jack = one(p for p in people if p.id == '1234')

sqlalchemy already has such a function for queries:
https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one

This is my implementation:

def one(iterable):
it = iter(iterable)
try:
r = next(it)
except StopIteration:
raise ValueError("Iterator is empty")
try:
next(it)
except StopIteration:
return r
else:
raise ValueError("Iterator has more than one item")

What do you think?

Thanks,
Noam
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/
Code of Conduct: http://python.org/psf/codeofconduct/