Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
216 views
in Technique[技术] by (71.8m points)

python - Why are arbitrary target expressions allowed in for-loops?

I accidentally wrote some code like this:

foo = [42]
k = {'c': 'd'}

for k['z'] in foo:  # Huh??
    print k

But to my surprise, this was not a syntax error. Instead, it prints {'c': 'd', 'z': 42}.

My guess is that the code is translated literally to something like:

i = iter(foo)
while True:
    try:
        k['z'] = i.next()  # literally translated to assignment; modifies k!
        print k
    except StopIteration:
        break

But... why is this allowed by the language? I would expect only single identifiers and tuples of identifiers should be allowed in the for-stmt's target expression. Is there any situation in which this is actually useful, not just a weird gotcha?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The for loop follows the standard rules of assignment so what works on the LHS of a vanilla assignment should work with the for:

Each item in turn is assigned to the target list using the standard rules for assignments

The for construct simply summons the underlying mechanism for assigning to the target which in the case of your sample code is STORE_SUBSCR:

>>> foo = [42]
>>> k = {'c': 'd'}
>>> dis.dis('for k["e"] in foo: pass')
  1           0 SETUP_LOOP              16 (to 18)
              2 LOAD_NAME                0 (foo)
              4 GET_ITER
        >>    6 FOR_ITER                 8 (to 16)
              8 LOAD_NAME                1 (k)
             10 LOAD_CONST               0 ('e')
             12 STORE_SUBSCR <--------------------
             14 JUMP_ABSOLUTE            6
        >>   16 POP_BLOCK
        >>   18 LOAD_CONST               1 (None)
             20 RETURN_VALUE

But to my surprise, this was not a syntax error

Apparently, whatever works in a regular assignment such as the following:

full slice assignment:

>>> for [][:] in []:
...    pass
... 
>>>

list subscription

>>> for [2][0] in [42]:
...    pass
... 
>>> 

dictionary subscription etc. would be valid candidate targets, with the lone exception being a chained assignment; although, I secretly think one can cook up some dirty syntax to perform the chaining.


I would expect only single identifiers and tuples of identifiers

I can't think of a good use case for a dictionary key as a target. Besides, it is more readable to do the dictionary key assignment in the loop body, than use it as a target in the for clause.

However, extended unpacking (Python 3) which is very useful in regular assignments also comes equally handy in a for loop:

>>> lst = [[1, '', '', 3], [3, '', '', 6]]
>>> for x, *y, z in lst:
...    print(x,y,z)
... 
1 ['', ''] 3
3 ['', ''] 6

The corresponding mechanism for assigning to the different targets here is also summoned; multiple STORE_NAMEs:

>>> dis.dis('for x, *y, z in lst: pass')
  1           0 SETUP_LOOP              20 (to 22)
              2 LOAD_NAME                0 (lst)
              4 GET_ITER
        >>    6 FOR_ITER                12 (to 20)
              8 EXTENDED_ARG             1
             10 UNPACK_EX              257
             12 STORE_NAME               1 (x) <-----
             14 STORE_NAME               2 (y) <-----
             16 STORE_NAME               3 (z) <-----
             18 JUMP_ABSOLUTE            6
        >>   20 POP_BLOCK
        >>   22 LOAD_CONST               0 (None)
             24 RETURN_VALUE

Goes to show that a for is barely simple assignment statements executed successively.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...