Изменение функции сравнения для использования ключей для сортировки - PullRequest
3 голосов
/ 02 февраля 2011

У меня есть следующий код, написанный на Python 2.6, с классом Task, который имеет необязательный due_date:

class Task(models.Model):
    due_date = models.DateField(null = True, blank = True)

    @staticmethod
    def compare_by_due_date(t1, t2):
        return due_date_cmp(t1.due_date, t2.due_date)

def due_date_cmp(t1, t2):
    if t1 is None and t2 is None:
        return 0;
    if t1 is None:
        return 1
    if t2 is None:
        return -1
    return (t1 - t2).days

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

tasks = Task.objects.all()
tasks.sort(Task.compare_by_due_date)

Я понял из этого ответа на Code Review , что я должен иметь возможность использовать ключи вместо функции сравнения ? Можете ли вы показать мне, как?

Ответы [ 2 ]

4 голосов
/ 02 февраля 2011

Вы не можете сравнивать объекты всех разных типов (например, datetime.date с None), даже если 2.x допускает больше сравнений между различными типами, чем 3.x, поэтому прямое сравнение due_dates не будет работать.

def due_date_key(t):
  return (t.due_date is None, t.due_date)

tasks.sort(key=due_date_key)

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

2 голосов
/ 02 февраля 2011

Похоже, due_date_cmp сортирует список, состоящий из datetime.date и None объектов, помещая None s в конец списка.

Вы можете сделать то же самое, используя клавишукоторый преобразует None объектов в максимально возможный datetime.date объект:

старый способ (с использованием cmp):

import datetime as dt

def due_date_cmp(t1, t2):
    if t1 == None and t2 == None:
        return 0;
    if t1 == None:
        return 1
    if t2 == None:
        return -1
    return (t1 - t2).days


dates=[dt.date(2000,1,1),None,dt.date(1999,1,1),None,dt.date(2002,1,1)]
dates.sort(cmp=due_date_cmp)
print(dates)
# [datetime.date(1999, 1, 1), datetime.date(2000, 1, 1), datetime.date(2002, 1, 1), None, None]

новый способ (с использованиемключ):

def due_date_key(t):
    if t is None:
        return dt.date(dt.MAXYEAR,12,31)
    else:
        return t

dates=[dt.date(2000,1,1),None,dt.date(1999,1,1),None,dt.date(2002,1,1)]
dates.sort(key=due_date_key)
print(dates)

# [datetime.date(1999, 1, 1), datetime.date(2000, 1, 1), datetime.date(2002, 1, 1), None, None]

Таким образом, вы можете использовать due_date_key в своем коде так:

import operator
class Task(models.Model):
    @property
    def due_date_key(self):
        due_date=self.due_date
        if due_date is None:
            return dt.date(dt.MAXYEAR,12,31)
        else:
            return due_date

tasks = Task.objects.all()
tasks.sort(key=operator.attrgetter('due_date_key'))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...