2

The second argument of the iter function is useful for looping over objects that don't define themselves as iterable, such as binary files:

response = b''
for block in iter(partial(f.read, 256), b''):
    response += block

However in Python 3.8 we now have the “the walrus operator”, which in the What's new in Python 3.8 article is mentioned as way to solve the exact problem above:

# Loop over fixed length blocks
while (block := f.read(256)) != '':
    process(block)

I wonder if the later is now considered "the right approach"? And if so, if there is ever any need for the second argument of iter, since any code on the form

for x in iter(f, y):
    g(x)

might as well now be written:

while (x := f()) != y:
    g(x)

I guess there might still be cases where we don't want to immediately loop the iterable, such as b''.join(iter(partial(f.read, 256), b'')) or some code (though it quickly gets pretty hairy). Also a loop like for i, x in enumerate(iter(f, y)): might be hard to translate to the new syntax(?)

The PEP for walrus only mentions 2-arg iter in the example while h(x := f()): g(x), which it says can't trivially be translated to iter.

Python usually have pretty precise guidelines on these sorts of things, but I haven't been able to find any for this particular issue. Can you help me?

Thomas Ahle
  • 30,774
  • 21
  • 92
  • 114
  • 2
    `f.read(256)` isn't a valid first argument to the 2-argument form of `iter`; I think you mean `iter(lambda: f.read(256), b'')`. – chepner Jan 26 '20 at 19:31
  • 1
    I believe since this a a very new feature, it will take a little while to see which becomes the dominant feature in this context and what are the pros and cons of each. – Olivier Melançon Jan 26 '20 at 19:32
  • 1
    `iter(..., ...)` would still be useful as a starting point for building an iterator, for example, using the types defined by the `itertools` module. – chepner Jan 26 '20 at 19:32
  • From a completely different perspective, one might argue that `iter(callable, sentinel)` was *never* Pythonic, given how rarely it is seen. :) – chepner Jan 26 '20 at 19:41
  • How then did it become the recommendation of "Transforming Code into Beautiful, Idiomatic Python" :P. I suppose it was just pushed but never adopted... Maybe it should just be removed then. – Thomas Ahle Jan 26 '20 at 19:44

1 Answers1

2

The assignment expression is useful if you are primarily interested in immediately iterating over the iterator, but it doesn't help you define an iterator to be used elsewhere.

For example, you may want to create an iterator that will first be wrapped in map, or filter, or itertools.islice, before finally iterating over the final result using a for loop.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • I suppose you could use `(x for _ in count() if (x := f()) != y)` as a walrus version of `iter(f, y)`. – Thomas Ahle Jan 26 '20 at 19:37
  • Though I get your point: Use walrus for loops, and use `iter` for creating iterators not to be immediately looped over. – Thomas Ahle Jan 26 '20 at 19:38
  • And even in `while` loops, I think `:=` is best used for simple assignments and checks. There is probably code that's still best written using `while True: x = f(x); if : break; ...` – chepner Jan 26 '20 at 19:39
  • 1
    Even that's still slightly different: that generator goes for ever, rather than stopping when `x == y`. – chepner Jan 26 '20 at 19:40
  • Good point. I guess the case of non-iteration is clear then. And you are right, in the case of while loops there were already two ways to do it. – Thomas Ahle Jan 26 '20 at 19:42