Почему это понимание списка не делает то, что я ожидаю? - PullRequest
3 голосов
/ 30 мая 2010

Первоначальный список project_keys = sorted(projects.keys()) равен [101, 102, 103, 104, 105, 106, 107, 108, 109, 110], где следующие проекты были признаны invalid в этом году: 108, 109, 110.

Таким образом:

for project in projects.itervalues():
# The projects dictionary is mapped to the Project class
    if project.invalid:
    # Where invalid is a Bool parameter in the Project class
     project_keys.remove(project.proj_id)  

print project_keys

Это вернет список целых чисел (которые являются идентификаторами проекта) в следующем виде:

[101, 102, 103, 104, 105, 106, 107]

Сладкое.

Теперь я хотел, чтобы он попробовал то же самое, используя понимание списка.

project_keys = [project_keys.remove(project.proj_id) for project in projects.itervalues() if project.invalid  

print project_keys

Возвращает:

[None, None, None]

Итак, я заполняю список тем же номером, что и удаленные элементы, но они None s?

Может кто-нибудь указать, что я делаю не так?

Кроме того, зачем мне использовать понимание списка над блоком for-if вверху? Лаконичность? Выглядит лучше?

Ответы [ 2 ]

6 голосов
/ 31 мая 2010

Ваше понимание списка работает с использованием побочных эффектов. Просто выполните его, обновите project_keys, чтобы получить желаемый результат.

[project_keys.remove(project.proj_id)
 for project in projects.itervalues()
 if project.invalid]

Возвращаемое значение из remove равно None. Присвоив результат понимания списка project_keys, вы ошибаетесь.

Простой цикл, вероятно, здесь более понятен. Понимание списка, использующее побочные эффекты, может сбить с толку.

Однако вы можете решить свою проблему немного иначе:

project_keys = sorted(project.proj_id
                      for project in projects.itervalues()
                      if not project.invalid)

Это сохраняет проекты, которые вас интересуют, вместо удаления тех, которые вас не интересуют. В приведенном выше примере вместо выражения списка используется выражение генератора, но оно будет работать с любым из них.

4 голосов
/ 31 мая 2010

Вы, сэр, неправильно поняли списочные представления.

Что вы, вероятно, хотели (на словах)

Я хочу удалить все недействительные идентификаторы проекта.

Что вы написали

project_keys = [project_keys.remove(project.proj_id)
                for project in projects.itervalues() if project.invalid]

Что на самом деле происходит

dummy = []
for project in projects.itervalues():
  if project.invalid:
    dummy.append(project_keys.remove(project.proj_id)) #what are you
project_keys = dummy                                   #removing items from?
del dummy                                            

Что на самом деле происходит (теперь с более «функциональным»)

mapped-fun = lambda project: project_keys.remove(project.proj_id)
filtering-fun = lambda project: project.invalid
project_keys = map(mapped-fun, filter(filtering-fun, projects.itervalues()))

Как видите, списочные выражения - это , а не синтаксический сахар вокруг for циклов. Скорее, списочные выражения являются синтаксическим сахаром вокруг map() и filter(): применить функцию ко всем элементам в последовательности , которые сопоставьте условие и получите в ответ список результатов.

Здесь под функцией фактически подразумевается преобразование ввода в вывод без побочных эффектов. Это означает, что вы «не можете» использовать методы, которые изменяют сам ввод, например list.sort(); вам придется использовать их функциональные эквиваленты, такие как sorted().

Однако под словом «не могу» я не имею в виду, что вы будете получать сообщения об ошибках или носовые демоны ; Я имею в виду, что вы злоупотребляете языком. В вашем случае, оценка понимания списка, которое происходит, когда вы присваиваете его переменной, действительно дает ожидаемые побочные эффекты - но вызывает ли это их на предполагаемых переменных?

Видите ли, единственная причина, по которой это может выполняться без ошибок, состоит в том, что до этого понимания списка был другой список, называемый project_keys, и этот список, который вы фактически меняете !

Понимание списков является результатом функционального программирования, которое отвергает побочные эффекты. Помните об этом при использовании списочных представлений.


Итак, вот мыслительный процесс, который вы можете использовать, чтобы действительно получить понимание списка, которое вы хотели.

Что вы на самом деле хотели (словами)

Я хочу, чтобы все идентификаторы проекта были действительными (= недействительными).

Что вы на самом деле хотели

dummy = []
for project in projects.itervalues():
  if not project.invalid:
    dummy.append(project.proj_id)
project_keys = dummy
del dummy

То, что вы на самом деле хотели (теперь с более функциональным)

mapped-fun = lambda project: project.proj_id
filtering-fun = lambda project: not project.invalid
project_keys = map(mapped-fun, filter(filtering-fun, projects.itervalues()))

Что вы на самом деле хотели (теперь для понимания списка)

project_keys = [project.proj_id for project in projects.itervalues()
                if not project.invalid]
...