#python #python-3.x #python-2.7 #generator #dictionary-comprehension
#python #python-3.x #python-2.7 #генератор #словарь-понимание
Вопрос:
Я получаю неожиданное поведение в Python при использовании генератора, вложенного в понимание, понимание словаря в данном конкретном случае ниже. Более конкретно, рассмотрим следующее простое понимание:
D = {x : (y for y in range(5) if y==x) for x in range(5)}
Я ожидал бы получить такой словарь D
, что list(D[x]) == [x]
для каждого целого числа i от 0 до 4. Вместо этого результат
>>> list(D[0])
[4]
>>> list(D[1])
[4]
>>> list(D[2])
[4]
>>> list(D[3])
[4]
>>> list(D[4])
[4]
Я думаю, что это происходит потому, что значение переменной x
, используемой для определения генератора, меняется до тех пор, пока не будет зафиксировано на 4. Однако я подумал, что каждый генератор должен определяться с точным значением переменной во время определения. Есть ли альтернативный способ исправить эту простую вложенную структуру исправленным способом и с ожидаемыми результатами?
Обратите внимание, что преобразование генератора в список исправит поведение:
D = {x : list((y for y in range(5) if y==x)) for x in range(5)}
но меня интересуют решения, которые сохраняют использование генераторов.
Комментарии:
1. Каждый генератор будет выдавать только один элемент; зачем беспокоиться? Или вы думаете, что один генератор будет использоваться всеми 5 ключами? Это не так, как
dict
работает.2.
x
это просто свободная переменная внутри генератора; ее значение не будет просматриваться до тех пор, пока вы фактически не выполните итерацию по генератору.3. Непонятно, зачем вам нужно внутреннее понимание?
lambda
Вместо этого используйте a!4. Этот пример — всего лишь игрушечный пример, позволяющий легко исследовать это неожиданное поведение, вдохновленное более значимым случаем
Ответ №1:
x
является свободной переменной, поэтому ее значение не будет учитываться до тех пор, пока вы фактически не выполните итерацию по генератору. Это, как вы заметили, означает, что значение x
может меняться в промежутке между определением генератора и его фактическим использованием.
Невозможно передать значение в выражение генератора; вам придется использовать функцию генератора:
def make_generator(x):
for y in range(5):
if y == x:
yield y
D = {x: make_generator(x) for x in range(5)}
Ответ №2:
Для сценария, который вы описали (я не понимаю, зачем вам нужно внутреннее понимание), вы можете просто использовать следующее:
d = {x:lambda x: [x] for x in range(5)}
print(d[3](3))
который даст:
[3]