python - 为什么 for 循环中允许任意目标表达式?

标签 python for-loop language-lawyer

我不小心写了一些这样的代码:

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

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

但令我惊讶的是,这不是语法错误。相反,它会打印 {'c': 'd', 'z': 42}

我的猜测是该代码按字面意思翻译为:

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

但是...为什么语言允许这样做?我希望 for-stmt's target expression 中只允许单个标识符和标识符元组。 .在任何情况下这实际上是有用的,而不仅仅是一个奇怪的问题?

最佳答案

for 循环遵循标准的赋值规则,因此在普通赋值的 LHS 上工作的内容应该与 for 一起工作:

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

for 构造只是调用分配给目标的底层机制,在您的示例代码中是 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

显然,任何在常规作业中有效的方法,例如:

完整切片分配:

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

列表订阅

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

字典订阅等将是有效的候选目标,唯一的异常(exception)是链式分配;不过,我暗中认为可以编写一些肮脏的语法来执行链接。


I would expect only single identifiers and tuples of identifiers

我想不出一个将字典键作为目标的好的用例。此外,在循环体中进行字典键分配比在 for 子句中使用它作为目标更具可读性。

然而,在常规赋值中非常有用的扩展解包(Python 3)在 for 循环中也同样方便:

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

这里也召唤了相应的分配给不同目标的机制;多个STORE_NAME:

>>> 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

说明 for 只是简单的连续执行的赋值语句。

关于python - 为什么 for 循环中允许任意目标表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44317993/

相关文章:

python - ImproperlyConfigured 设置 xxxx 环境变量 - django-environ

python - 使用循环动态查找序数 : find th - st - nd - rd

r - 根据特定列中的数据框条目添加新列的最快方法是什么

python - 将 nan 值替换为分类变量中用户定义的值

python - 包装器的循环参数要求

python - 为什么 collections.OrderedDict 使用 try 和 except 来初始化变量?

r - 在R中,如何确定一个整数是否可以被一个数整除?

javascript - JavaScript 数学函数 (atan2) 的最后一位数字的浏览器差异是否在规范范围内?

c - 使用外部链接声明的对象的外部定义

c++ - 如何为模板类的 const ref 成员定义 move 赋值运算符