Есть ли лучший способ, чем лямда для фильтрации атрибутов/методов объектов?


Есть ли лучше (более подходящие для Python?) способ фильтровать список по атрибутам и методам объектов не полагаться на функции лямбда?

contexts_to_display = ...
tasks = Task.objects.all()
tasks = filter(lambda t: t.matches_contexts(contexts_to_display), tasks)
tasks = filter(lambda t: not t.is_future(), tasks)
tasks = sorted(tasks, Task.compare_by_due_date)

Здесь, matches_contexts и is_future методы задач. Я должен сделать эти бесплатные функции, чтобы иметь возможность использовать фильтр(is_future, задачи)?

Любой другой комментарий?



14678
1
задан 1 февраля 2011 в 10:02 Источник Поделиться
Комментарии
4 ответа

Я хотел бы использовать список понимание:

contexts_to_display = ...
tasks = [t for t in Task.objects.all()
if t.matches_contexts(contexts_to_display)
if not t.is_future()]
tasks.sort(cmp=Task.compare_by_due_date)

Поскольку у вас уже есть список, я не вижу причин не сортировать его напрямую, и это упрощает код немного.

Параметр ЦМП сайта-это больше напоминание о том, что это 2.X код и должны быть изменены, чтобы использовать ключ в 3.X (но можно запустить с помощью ключа теперь тоже):

import operator
tasks.sort(key=operator.attrgetter("due_date"))
# or
tasks.sort(key=lambda t: t.due_date)

Вы можете совместить понимание и сортировки, но это, наверное, менее читабельным:

tasks = sorted((t for t in Task.objects.all()
if t.matches_contexts(contexts_to_display)
if not t.is_future()),
cmp=Task.compare_by_due_date)

7
ответ дан 2 февраля 2011 в 11:02 Источник Поделиться

Поскольку вы пишете код в Django, вы не нужны лямбды вообще (объяснение ниже). В другом коде Python, вы могли бы хотеть использовать списочные включения, как в других комментариях уже упоминали. лямда -с мощная концепция, но они чрезвычайно искалеченных в Python, так что вы лучше с петель и списочные.

Теперь для исправления Джанго.

tasks = Task.objects.all()

задачи - это объект QuerySet. Объект QuerySetс ленивые-оценка, т. е. актуальный SQL-запрос к базе данных откладывается на последний момент. Так как вы используете лямбда-выражения, вы на самом деле группа Джанго делать дорогую выберите * ОТ ... и фильтра все вручную и в памяти, вместо того, чтобы позволить базе данных делать свою работу.

contexts_to_display = ...

Если эти контексты экземпляров модели в Джанго, то вы можете быть более эффективным с запросами и поля, а не отдельных методов:

# tasks = Task.objects.all()
# tasks = filter(lambda t: t.matches_contexts(contexts_to_display), tasks)
# tasks = filter(lambda t: not t.is_future(), tasks)
# tasks = sorted(tasks, Task.compare_by_due_date)
qs = Task.objects.filter(contexts__in=contexts_to_display, date__gt=datetime.date.today()).order_by(due_date)
tasks = list(qs)

Последняя строка вызовет Джанго возможность реально оценить объект QuerySet и таким образом отправить SQL-запрос в базу данных. Таким образом, вы могли бы также хотеть вернуться СМО вместо задач и перебирайте его в ваш шаблон.

3
ответ дан 11 февраля 2011 в 10:02 Источник Поделиться

Я думаю, что лямбды-нормально в этом случае. (Да, не очень хороший обзор код, но что я могу сказать... Вы в основном задаете вопросы типа Да/нет. Ответ: "Нет". :) )

2
ответ дан 2 февраля 2011 в 12:02 Источник Поделиться

Первая лямбда (называя matches_contexts) не может быть избегать, поскольку оно должно захватить contexts_to_display, но не is_future() могут быть перемещены в новый целевой метод can_start_now: это яснее (скрывая негативные условия), многоразовые, и это состояние, скорее всего, будет сложнее в будущем. Да, YAGNI, я знаю... ;)

И потому что мне не нужна сортировка этапе вернуть один экземпляр задачи, я использовал сортировку на месте. Кстати, аргументы перепутаны между фильтром(Ф повторяемое) и отсортированный(повторяемое,Ф), используя один просто за другим показались неудобны...

Поэтому код сейчас:

class Task:
...
def can_start_now(self):
return not self.is_future()

contexts_to_display = ...
tasks = Task.objects.all()
tasks = filter(lambda t: t.matches_contexts(contexts_to_display), tasks)
tasks = filter(Task.can_start_now, tasks)
tasks.sort(Task.compare_by_due_date)

0
ответ дан 2 февраля 2011 в 08:02 Источник Поделиться