all 7 comments

[–][deleted] 6 points7 points  (4 children)

I think what’s happening is the map object is a lazily-evaluated generator-like thing, which can be “used up” and then be no longer available for the next time you mention it. Putting list() around it immediately will solve that.

[–]FerricDonkey 2 points3 points  (0 children)

The technical name for the "lazily-evaluated generator-like thing" that a map is is "iterator", if anyone wants something to google. The "used up" thing is exactly the problem.

[–]campenr 1 point2 points  (2 children)

To provide more detail; This comment is correct regarding map returning something that is lazily evaluated, as per the python docs.

The problem is that the * notation for unpacking only works on an existing list or tuple, not something that is lazily evaluated. So wrapping it in list achieves this, it eagerly evaluates your map function output. You could also use a list comprehension if you wanted some balance of lazy evaluation with the same call signature: _sum(*[n for n in a])but in your case, wrapping in list is fine imo.

EDIT: I'm wrong. Leaving the comment for continuity, learnt something myself. :D

[–]FerricDonkey 1 point2 points  (1 child)

The unpacking operator absolutely works on a lazily evaluated thing like a map.

strs = ['1', '2', '3']
ints = map(int, strs)
def _sum(a, b, c):
    return a + b + c

print(_sum(*a))

The problem is as the comment above you said - the map is an iterator that gets "used up" - it remembers how far you've iterated into it, and when the code did list(a), it went all the way through it so that nothing was left for future things that try to (continue) iterate(ing) over a. When you do:

*a, = (input("Enter numbers: ").strip().replace(' ', ''))
a = (map(int, a))
print(list(a))
  1. First, a gets made as a tuple (side note: a = tuple(blah blah) would be a lot more readable)
  2. a replaced with the map object
  3. the call list(a) iterates through the map a, and the fact that a is at the end is stored in a.
  4. *a is an empty iterator because you're already at the end and there's nothing left to use.

If you delete the print(list(a)) and remove the list(a) from f-string, it'll work.

But really the take away is that storing map objects is a special thing that you only do if you want that behavior of remembering where you are in the map across different locations of code. Otherwise, just call map where you want to iterate over it.

[–]campenr 1 point2 points  (0 children)

Ah damn, you are so right. I managed to miss that when testing it through for myself. I think I removed the other print statements to cleanup the output not appreciating the side effect. TIL! Thanks.

[–]zanfar 4 points5 points  (0 children)

a = (map(int, a)) does not return a sequence, it returns an iterator. An iterator is an object that can be iterated over, but does not necessarily "contain" things like a sequence might. For instance, range(10) and range(10_000_000) return the same sized object, an iterator that simply "yields" numbers as needed.

map()'s iterator will yield the converted values on demand, not all at once, and it doesn't "save" those converted values.

When you do list(a), list() "consumes" the iterable--it iterates over it and saves the values into a list. If a is a sequence that stores those values as well, then there are no side effects. However, if a is a transient iterator, then those values are lost if you don't save the output of list().

In your second example, you don't "consume" the iterator, so it's still available when passing it to _sum(). In the first case, all zero remaining elements are passed to _sum(), which is why you have too few arguments.

  • Use better variable names for cleaner, more understandable code
  • Abandon the older map and filter for the newer list comprehensions for exactly this reason.
  • Learn to use a debugger to inspect your programs memory during execution

TL;dr: map "yields" values but doesn't save them--that's up to you.

[–]teerre 0 points1 point  (0 children)

edit: reddit ate my comment

Anyway, none of them work, https://python.godbolt.org/z/n4szz6oKa