Переопределить оператор +, чтобы сделать дату + время = datetime в Python - PullRequest
7 голосов
/ 08 ноября 2010

У меня есть пара классов, расширяющих встроенную дату и время. *

Есть ли веская причина не перегружать + (MyTime.__radd___), поэтому MyDate + MyTime возвращает MyDateTime?

Ответы [ 6 ]

16 голосов
/ 08 ноября 2010

Это уже реализовано как метод класса, datetime.datetime.combine:

import datetime
d = datetime.date(2010, 12, 5)
t = datetime.time(10, 22, 15)
dt = datetime.datetime.combine(d, t)
print dt

печать

2010-12-05 10:22:15
12 голосов
/ 08 ноября 2010

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

Мне не известны какие-либо другие случаи в Python, когда <instance of TypeA> + <instance of TypeB> производит <instance of TypeC>. Таким образом, Принцип наименьшего удивления предполагает, что вы должны просто предоставить combine метод, а не сложение с перегрузкой.

4 голосов
/ 07 января 2012

Да, есть хотя бы одна веская причина не делать этого: результирующий экземпляр полностью отличается от двух входных экземпляров.Это важно?Я так не думаю - считайте, что date - date дает timedelta.

То, как я это вижу:

  • Имеет ли смысл добавлять две даты вместе?Нет.
  • Имеет ли смысл добавлять два раза вместе?Нет.
  • Имеет ли смысл добавлять дату и время вместе?Ага!
  • Имеет ли смысл добавление даты и таджетора timedelta?Может быть.
  • Имеет ли смысл добавлять время и временную дельту вместе?Может быть.

и для вычитания

  • Имеет ли смысл вычитание двух дат?Да.
  • Имеет ли смысл вычитать два раза?Да.
  • Имеет ли смысл вычитать время из даты?Нет.
  • Имеет ли смысл вычитать временную дельту из даты?Может быть.
  • Имеет ли смысл вычитать временную дельту из времени?Может быть.

Развитие в соответствии с тем, что имеет смысл:

date + time      => datetime
date + timedelta => date | datetime or exception or silently drop time portion

time + date => datetime
time + timedelta => time | wrap-around or exception

date - date      => timedelta
date - timedelta => date | datetime or exception or silently drop time portion

time - time      => timedelta
time - timedelta => time | wrap-around or exception

datetime + timedelta => datetime
datetime - timedelta => datetime

Итак, если бы я и я проектировали фреймворк Date, Time, DateTime, TimeDelta, япозволит:

date + time
date - date
time - time
datetime + timedelta
datetime - timedelta

и для них:

date +/- timedelta
time +/- timedelta

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

1 голос
/ 13 января 2012

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

concat(concat(concat("Hello", ", "), concat("World", "!")), '\n');

или

distance = sqrt(add(add(x*x, y*y), z*z));

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

С вашими date + time = datetime не имеет смысла добавлять datetime + datetime, datetime + time или datetime + dateТаким образом, вы никогда не могли столкнуться с ситуацией, подобной приведенной выше.

По моему мнению, еще раз, правильная вещь - это использовать метод конструктора.В языке со строгой типизацией, таком как C ++, у вас будет DateTime(const Date &d, const Time &t).С динамической типизацией Python, я думаю, они дали функции имя datetime.combine(date, time), чтобы сделать код более понятным, когда типы входных переменных не видны в коде.

1 голос
/ 12 января 2012

Из-за существования операторов сложения и вычитания перекрестного типа даты, времени и даты и времени я думаю, что это хорошо, если только они четко определены.

В настоящее время (2.7.2):

date = date + timedelta
date = date - timedelta
timedelta = date - date

datetime = datetime + timedelta
datetime = datetime - timedelta
timedelta = datetime - datetime

Я считаю, что для расширения также целесообразно:

timedelta = time - time
datetime = date + time

Я собирался также предложить следующее, но time имеет очень конкретные минимальные и максимальные значения для hour, minute, second и microsecond, таким образом, требуя тихого переноса значений или возвращение другого типа:

time = time + timedelta
time = time - timedelta

Аналогичным образом, date не может обработать timedelta менее чем за один день, добавляемый к нему. Часто мне говорили просто использовать Duck Typing с Python , потому что таково намерение. Если это правда , то я бы предложил следующий завершенный интерфейс:

[date|datetime] = date + timedelta
[date|datetime] = date - timedelta
timedelta = date - date

[time|timedelta] = time + timedelta
[time|timedelta] = time - timedelta
timedelta = time - time

datetime = datetime + timedelta
datetime = datetime - timedelta
datetime = date + time
datetime = date - time
timedelta = datetime - datetime
timedelta = datetime - date

timedelta = timedelta + timedelta
timedelta = timedelta - timedelta

В этом случае, учитывая, что date имеет потерю точности (для timedelta с частичными днями), оно повышается до datetime. Точно так же, учитывая случай, когда time имеет потерю точности (для timedelta, которые дают результат более одного дня или отрицательного времени), он повышается до timedelta. Однако , мне не совсем комфортно с [time|timedelta]. Это имеет смысл, учитывая остальную часть интерфейса из параллелизма и точности представлений, но я думаю, что было бы более элегантно просто перенести время на нужный час, таким образом, изменив все [time|timedelta] на просто time, но к сожалению, это оставляет нас с потерянной точностью.

0 голосов
/ 11 января 2012

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

Если мы сравним его с datetime.combine, то, что combine сделает:

dt = date(2011,01,01)
tm = time(20,00)
dtm = datetime.combine(dt, tm)

Для дтм

  • Если dt является объектом даты, а tm является объектом времени, тогда информация date берется из dt, time info и tzinfo взято из tm объекта
  • , если dt является объектом datetime , тогда его атрибуты time и tzinfo будут игнорироваться.

С этой точки зрения работа с datetime объектами представляется не просто объектами, а более сложными структурами с различными атрибутами, такими как информация о часовом поясе .

Вероятно, поэтому datetime объекты имеют некоторые дополнительные функции, которые используются для форматирования типа объекта и структуры данных объекта.

У Python есть девиз (что-то подобное):

В python нет ничего неизменного, если , вы знаете, что делаете. Если нет, то лучше оставить библиотечные функции такими, какие они есть ...

Так что, на мой взгляд, лучше использовать combine с перегрузкой + оператор

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...