[英]Can't use locals() in list comprehension in Python 3?
以下適用於 Python 2 但不適用於 3。有沒有辦法在 Python 3 中訪問局部變量? 或者這些情況的替代解決方案?
[('{name_var}_{i:02d}of{maxpg:02d}.{date_var}').format(i, **locals())
for i in range(start, end)]
Python 3 中的錯誤:
KeyError: 'local_var'
下面是上面的一個更簡單的玩具示例(適用於 Python 2 但不適用於 Python 3)
local_var = 'hello'
['{local_var}'.format(**locals()) for i in range(1)]
Python 3 中的錯誤:
KeyError: 'local_var'
正如@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
函數在列表推導執行之前被調用,迭代器被構建並傳遞給列表推導。
關於您的具體問題,您可以強制對列表理解之外的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']
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.