Reputation:
Suppose I have a silly function, like FizzBuzz:
>>> def FizzBuzz(i):
... if i % 15 == 0:
... return "FB"
... elif i % 3 == 0:
... return "F"
... elif i % 5 == 0:
... return "B"
... else:
... return i
And a list:
>>> li=list(range(1,22))
>>> li
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
Now if I do a generator expression applying that function to the list:
>>> ge=(FizzBuzz(x) for x in li)
>>> ge
<generator object <genexpr> at 0x1063ca3a8>
I can turn that into a list (i.e., run the generator expression):
>>> list(ge)
[1, 2, 'F', 4, 'B', 'F', 7, 8, 'F', 'B', 11, 'F', 13, 14, 'FB', 16, 17, 'F', 19, 'B', 'F']
Now suppose I do a slice assignment rather than an assignment to a separate name:
>>> li=list(range(1,22))
>>> li[:]=(FizzBuzz(x) for x in li)
>>> li
[1, 2, 'F', 4, 'B', 'F', 7, 8, 'F', 'B', 11, 'F', 13, 14, 'FB', 16, 17, 'F', 19, 'B', 'F']
You can see that the generator expression is immediately executed.
Same with map
:
>>> map(FizzBuzz, li)
<map object at 0x10640c358>
>>> li[:]=map(FizzBuzz, li)
>>> li
[1, 2, 'F', 4, 'B', 'F', 7, 8, 'F', 'B', 11, 'F', 13, 14, 'FB', 16, 17, 'F', 19, 'B', 'F']
Now suppose that FizzBuzz
is not a silly function, but rather a function that takes a while and li
is big enough that you want to do slice assignment.
Is there a way to defer the execution of the generator but still assign in place? (I do realize that I can just do ge=(f(x) for x in big_list); big_list[:]=list(ge)
which is a workaround...)
Upvotes: 0
Views: 189
Reputation: 881775
Clearly, (FizzBuzz(x) for x in li)
needs li
to be still "intact" when it starts running, since it must loop over it and get the right items.
So where would you want to "assign in place" -- what place do you have in mind?
Assigning it to a variable independent of li
, which you diss as "a workaround", is fine of course.
But where would you like to put it instead?!
Certainly not anywhere where it would trample on li
's contents until you're ready to run it, since we've already established that said contents must be intact when the generator starts running.
You could bind those contents with a def
, e.g
def doge(savedli=list(li)):
for x in savedli: yield FizzBuzz(x)
Now, li[:]=doge
will wipe away li
's contents, superficially, but still keep them safely stashed away in doge
(now set to li[0]
), so later you could do li[:] = doge()
. But I don't see any advantage in this more contorted approach.
So if this answer is not satisfactory, please clarify in what place you want to "assign in place" a generator, respecting of course the need for the list's original contents to survive somewhere until the generator starts running.
Upvotes: 1