Python: проблема при использовании словаря vars()
У меня есть следующий фрагмент:
a, b = 1, 2
params = ['a', 'b']
res = {p: vars()[p] for p in params}
Что дает мне KeyError: 'a'
, тогда как следующий код работает нормально:
a, b = 1, 2
params = ['a', 'b']
res = {}
for p in params:
res[p] = vars()[p]
Какая разница здесь?
Ответы
Ответ 1
vars()
без каких-либо аргументов действует как locals()
, и поскольку в понимании словаря есть своя область, у него нет переменной с именем a
или b
.
Здесь вы можете использовать eval()
. Без каких-либо аргументов он будет выполняться в LEGB или указать globals()
dict явно на eval
:
>>> res = {p: eval(p) for p in params}
>>> res
{'a': 1, 'b': 2}
Но опять же правильным способом будет создание словаря с самого начала, если вы хотите получить доступ к переменным, используя их имена.
Ответ 2
Из-за этого в вашем коде vars
возвращается словарь содержит переменные локальные. Фактически на основе документации:
Без аргумента vars() действует как locals().
см. следующий пример:
>>> def a():
... print vars()
...
>>> a()
{}
Как вы можете видеть, у нас нет какой-либо локальной переменной внутри функции a
, поэтому vars возвращает пустой словарь.
И в вашем случае как более питоническом способе вы можете создать словарь своих объектов:
d={'a':1,'b': 2,'params' : ['a', 'b']}
example_list : ['a', 'b']
res = {p: d[p] for p in example_list}
Ответ 3
Кажется, Python делает закрытие в понимании словаря (скажем, dictcomp
)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <dictcomp>
KeyError: 'a'
Ответ 4
Использовать vars()
в цикле for выполняет второй код, который вы указали.
# come out with {'a': 1, 'b': 2}
res = {p: v for p, v in vars().iteritems() if p in params}
res = {'a': vars()['a'], 'b': vars()['b']}
Мы можем найти новый locals/vars
в цикле for
в понимании dict:
>>> {i: list(vars().viewkeys()) if i == 0 else list(vars().viewvalues()) for i in range(2)}
{0: ['i', '.0'], 1: [1, <listiterator at 0x6fffe458550>]}
>>> {list(vars().viewkeys())[i]: list(vars().viewvalues())[i] for i in range(2)}
{'.0': <listiterator at 0x6fffe458710>, 'i': 0}