不能在Python 3的列表理解中使用locals()? [英] Can't use locals() in list comprehension in Python 3?
问题描述
以下内容在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屋!