Pythonic style

Stavros Macrakis macrakis at alum.mit.edu
Tue Sep 22 13:49:27 EDT 2020


Thanks to everyone for the comments, especially Tim Chase for the simple
and elegant tuple unpacking solution, and Léo El Amri for the detailed
comments on the variants. Below are some more variants which *don't *use
tuple unpacking, on the theory that the coding patterns may be useful in
other cases where unpacking doesn't apply.

For me, one of the interesting lessons from all these finger exercises is
that *for* and unpacking hide a lot of messiness, both the initial *iter* call
and the exception handling. I don't see any way to eliminate the *iter*,
but there are ways to avoid the verbose exception handling.

Using the second arg to *next*, we get what is arguably a more elegant
solution:


_uniq = []
def firstg(iterable):
    it = iter(iterable)
    val0 = next(it,_uniq)
    val1 = next(it,_uniq)
    if val0 is not _uniq and val1 is _uniq:
        return val0
    else:
        raise ValueError("first1: arg not exactly 1 long")


But I don't know if the *_uniq* technique is considered Pythonic.

If *next* were instead defined to return a flag (rather than raising an
exception), the code becomes cleaner and clearer, something like this:


def firsth(iterable):
  it = iter(iterable)
  (val0, good0) = next2(it)
  (val1, good1) = next2(it)  # val1 is dummy
  if good0 and not good1:
    return val0
  else:
    raise ValueError("first1: arg not exactly 1 long")

# returns (value, validp)

# validp is False if no more values

def next2(iterable):
  try:
    val = next(iterable)
  except StopIteration:
    return (None, False)
  return (val, True)


(To be clear, I'm *not *suggesting that *next2* replace *next*!)

Thoughts?

             -s


More information about the Python-list mailing list