如@user2357112在评论中解释的那样,在Python 3中,列表推导具有自己的局部作用域(因此也有locals()
字典)。
比较:
>>> 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
,而在第二个案例中,函数调用的结果作为参数传递给了列表推导式。
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
函数未被调用。您可以在列表推导式的代码中看到该调用:
>>> 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
函数在列表推导执行之前被调用,iter被构建并传递给列表推导。
关于你的具体问题,你可以强制在列表推导之外评估locals
(注意i=i
:这不是一个位置参数):
>>> 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字符串)[
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
一次并在列表推导式中使用它:
>>> format_string = '{name_var}_{{i:02d}}of{maxpg:02d}.{date_var}'.format(**locals())
>>> format_string
'VAR_{i:02d}of01.2019-01-01'
或者(>= 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 REPL所显示的。 - Antti Haapala -- Слава Україніlocals()
中。 - user2357112blah
的直接名称查找,例如[blah for thing in stuff]
,那么编译器将编译代码以执行额外的工作,以支持从推导式内部访问blah
。如果它只是调用locals
,例如[locals()['blah'] for thing in stuff]
,则编译器不会激活支持查找所需的机制。 - user2357112