不能在Python 3的列表理解中使用locals()? [英] Can't use locals() in list comprehension in Python 3?

查看:50
本文介绍了不能在Python 3的列表理解中使用locals()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下内容在Python 2中有效,但在3中无效.有没有办法在Python 3中访问局部变量?还是这些情况的替代解决方案?

The below works in Python 2 but not 3. Is there a way to access local variables in Python 3? Or an alternative solution to these cases?

[('{name_var}_{i:02d}of{maxpg:02d}.{date_var}').format(i, **locals()) 
  for i in range(start, end)]

Python 3 中的错误:

Error in Python 3:

KeyError:'local_var'

KeyError: 'local_var'

下面是上面的一个更简单的玩具示例(在Python 2中有效,但在3中无效)

Below is a simpler toy example of above (works in Python 2 but not 3)

local_var = 'hello'
['{local_var}'.format(**locals()) for i in range(1)]

Python 3中的错误

Error in Python 3:

KeyError:'local_var'

KeyError: 'local_var'

推荐答案

如@ user2357112在评论中所述,列表推导在Python中具有其自身的局部作用域(因此, locals() dict)3.

As explained by @user2357112 in a comment, list comprehensions have their own local scope (and thus locals() dict) in Python 3.

比较:

>>> var=1
>>> [locals() for _ in range(1)]
[{'_': 0, '.0': <range_iterator object at 0x7f5b65cb7270>}]

使用

>>> [l for l in (locals(), )]
[{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'var': 1}]

在第一种情况下,函数 locals 在列表理解代码内被调用,而在第二种情况下,函数调用的结果作为参数传递给列表理解.

In the first case, the function locals is called inside the list comprehension code while in the second the result of the function call is passed as an argument to the list comprehension.

dis 模块确认:

>>> from dis import dis
>>> def f(): return [locals() for _ in range(1)]
... 
>>> dis(f)
  1           0 LOAD_CONST               1 (<code object <listcomp> at 0x7fc8173bd9c0, file "<stdin>", line 1>)
              2 LOAD_CONST               2 ('f.<locals>.<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (range)
              8 LOAD_CONST               3 (1)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 RETURN_VALUE

未调用 locals 函数.您会在列表理解代码中看到该调用:

The locals function was not called. You see the call in the code of the list comprehension:

>>> dis(f.__code__.co_consts[1])
  1           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                10 (to 16)
              6 STORE_FAST               1 (_)
              8 LOAD_GLOBAL              0 (locals)
             10 CALL_FUNCTION            0
             12 LIST_APPEND              2
             14 JUMP_ABSOLUTE            4
        >>   16 RETURN_VALUE

虽然

>>> def g(): return [l for l in (locals(),)]
... 
>>> dis(g)
  1           0 LOAD_CONST               1 (<code object <listcomp> at 0x7f5b65cb8930, file "<stdin>", line 1>)
              2 LOAD_CONST               2 ('g.<locals>.<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (locals)
              8 CALL_FUNCTION            0
             10 BUILD_TUPLE              1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 RETURN_VALUE

在执行列表理解之前,将调用 locals 函数,该迭代器将构建并传递给列表理解.

The locals function is called before the list comprehension execution, the iter is built and passed to the list comprehension.

关于您的特定问题,您可以在列表理解之外强制评估 locals (请注意 i = i :这不是位置参数):

Concerning your specific problem, you can force the evaluation of locals outside of the list comprehension (note the i=i: this is not a positional argument):

>>> d = locals()
>>> ['{name_var}_{i:02d}of{maxpg:02d}.{date_var}'.format(i=i, **d) for i in range(start, end)]
['VAR_00of01.2019-01-01', 'VAR_01of01.2019-01-01', 'VAR_02of01.2019-01-01', 'VAR_03of01.2019-01-01', 'VAR_04of01.2019-01-01', 'VAR_05of01.2019-01-01', 'VAR_06of01.2019-01-01', 'VAR_07of01.2019-01-01', 'VAR_08of01.2019-01-01', 'VAR_09of01.2019-01-01']

如果您的Python版本是3.6或更高版本,则可以使用(f个字符串)[

If your version of Python is 3.6 or newer, you can use (f strings)[https://docs.python.org/3/whatsnew/3.6.html#pep-498-formatted-string-literals]

>>> [f'{name_var}_{i:02d}of{maxpg:02d}.{date_var}' for i in range(start, end)]
['VAR_00of01.2019-01-01', 'VAR_01of01.2019-01-01', 'VAR_02of01.2019-01-01', 'VAR_03of01.2019-01-01', 'VAR_04of01.2019-01-01', 'VAR_05of01.2019-01-01', 'VAR_06of01.2019-01-01', 'VAR_07of01.2019-01-01', 'VAR_08of01.2019-01-01', 'VAR_09of01.2019-01-01']

但是,我认为在每次迭代中在 locals()中进行查找不是一个好主意.您可以一次构建 format_string 并将其用于列表理解:

However, I think it's not a good idea to make a lookup in locals() for every iteration. You can build your format_string once and use it in the list comprehension:

>>> format_string = '{name_var}_{{i:02d}}of{maxpg:02d}.{date_var}'.format(**locals()) 
>>> format_string
'VAR_{i:02d}of01.2019-01-01'

或(> = 3.6):

Or (>= 3.6):

>>> format_string = f'{name_var}_{{i:02d}}of{maxpg:02d}.{date_var}'

那么你有:

>>> [format_string.format(i=i) for i in range(start, end)]
['VAR_00of01.2019-01-01', 'VAR_01of01.2019-01-01', 'VAR_02of01.2019-01-01', 'VAR_03of01.2019-01-01', 'VAR_04of01.2019-01-01', 'VAR_05of01.2019-01-01', 'VAR_06of01.2019-01-01', 'VAR_07of01.2019-01-01', 'VAR_08of01.2019-01-01', 'VAR_09of01.2019-01-01']

这篇关于不能在Python 3的列表理解中使用locals()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆