On Sat, Dec 7, 2019, 8:20 PM Andrew Barnert <abarnert@yahoo.com> wrote:
On Dec 7, 2019, at 07:33, Wes Turner <wes.turner@gmail.com> wrote:
>
> 
> +1 for itertools.first(seq, default=Exception) *and* itertools.one(seq, default=Exception)

What does default=Exception mean? What happens if you pass a different value? Does it do one thing if the argument is a type that’s a subclass of Exception (or of BaseException?) and a different thing if it’s any other value?

That's a good point: Exception is a bad sentinel value. Is None a good default value? What if the genexpr'd iterable is [None, 2, 3]


Also, why do you want these to be different from similar recipes like nth and first_true, and from the versions of exactly these functions in more_itertools, and the other related ones like only?

Also, “seq” implies that you’re expecting these to be used on sequences, not general iterables. In that case, why not just use [0]?

I chose `seq` as the argument because I was looking at toolz.itertoolz.first(),which has no default= argument.
Though, .first() (or .one()) on an unordered iterable is effectively first(shuffle(iterable)), which *could* raise an annotation exception at compile time. 

Sets are unordered iterables and so aren't sequences; arent OrderedIterables.


Arguably, first, and maybe some of it’s cousins, should go into the recipes. And I don’t see any reason they shouldn’t be identical to the versions in more-itertools, but if there is one, it should be coordinated with Erik Rose in some way so they stay in sync.

Oh hey, "more-itertools". I should've found that link in the cpython docs.

https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/more.html#first :
 
    def first(iterable, default=_marker)

That makes more sense than default=Exception. 

FWIW, more-itertools .one() raises ValueError (or whatever's passed as too_short= or too_long= kwargs). Default subclasses of ValueError may not be justified?


Maybe first is so useful, so much more so than all of the other very useful recipes, including things like consume, flatten, and unique (which IIRC were the ones that convinced everyone it’s time to add a more-itertools link to the docs), that it needs to be slightly more discoverable—e.g., by itertools.<TAB> completion? But that seems unlikely given that they’ve been recipes for decades and first wasn’t.

def itertools._check_more_itertools():
   """ https://more-itertools.readthedocs.io/en/stable/api.html """


And it seems even less likely for one, which nobody has mentioned in this thread yet.

If there’s a general argument that linking to more-itertools hasn’t helped anything, or that the recipes are still useless until someone makes the often-proposed/never-followed-through change of finding a way to make the recipes individually searchable and linkable, or whatever, that’s fine, but it’s not really an argument against making a special case for one that isn’t made for unique or consume.

Is programming by Exception faster or preferable to a sys.version_info conditional?

try:
   from itertools import one, first
except ImportError:
   from more_itertools.more import one, first

# Or:

if sys.version_info[:2] > (3,7);
   from itertools import one, first
else:
   from more_itertools.more import one, first

# Or, just:

# install_requires=["more-itertools"]
from more_itertools.more import one, first