2010-11-08 14 views
7

Tengo un par de clases que se extienden de fecha y hora incorporada. *de anulación del operador + para realizar fecha + hora = fecha y hora en Python

¿Hay alguna buena razón para no sobrecargar + (MyTime.__radd___) por lo MiFecha + MiHora devuelve un MyDateTime?

+0

La clase de tipo Haskell 'Number' define operadores aritméticos como' (+) 'como' Number a => a -> a -> a' (es decir, toma dos argumentos con un tipo que es una instancia de 'Number' y devuelve exactamente ese tipo). A veces deseo que otros idiomas con la sobrecarga del operador impongan tales restricciones. En Python, '+' es ** suma ** o ** concatenación **, nada más. Sobrecargarlo en un asunto completamente diferente solo ayuda a ... exagerar a las personas que creen que la sobrecarga del operador es horrible. ¿Qué hay de malo con el uso de una función/método para esto? – delnan

+1

@delnan: no pasa nada, la pregunta realmente fue sobre qué está mal con la sobrecarga y por qué combinar una fecha + hora es una operación tan distinta de la suma o la concatenación. –

+1

Puede agregar una propiedad o método 'medianoche' a' MyDate' (devolviendo 'MyDateTime'), y tal vez cambiar' MyTime' en 'MyTimeSpan', luego definir' __add__' tiene más sentido ('mydatetime = mydate.midnight + mytimespan'). – adw

Respuesta

12

Esto generalmente sería mal visto porque realmente se está combinando en lugar de agregar; esta es la razón por la que la biblioteca de fecha y hora real tiene un método combine en lugar de usar la adición de esta manera.

No tengo conocimiento de ningún otro caso en Python donde <instance of TypeA> + <instance of TypeB> produzca <instance of TypeC>. Por lo tanto, el Principle of least astonishment sugiere que simplemente debe proporcionar un método combine en lugar de sobrecargar la adición.

+5

Hay ejemplos de ' - ' produce' '. Por ejemplo, tome 'timedelta = datetime1 - datetime2'. –

16

Esto ya se implementa como un método de clase, 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 

impresiones

2010-12-05 10:22:15 
4

Sí, hay por lo menos una buena razón para no hacerlo: la instancia resultante es completamente diferente de la dos instancias de entrada. ¿Es esto importante? No lo creo, considere que date - date produce timedelta.

La forma en que lo veo:

  • lo hace la adición de dos fechas en conjunto tienen sentido? No.
  • ¿Tiene sentido agregar dos veces juntas? No.
  • ¿Tiene sentido agregar una fecha y un momento juntos? ¡Sip!
  • ¿Tiene sentido agregar una fecha y un timedelta? Tal vez.
  • ¿Tiene sentido agregar un tiempo y un timedelta juntos? Tal vez.

y para la sustracción

  • lo hace restando dos fechas tienen sentido? Sí.
  • ¿Restar dos veces tiene sentido? Sí.
  • ¿Restar restar un tiempo de una fecha tiene sentido? Nop.
  • ¿Tiene sentido restar un timedelta de una fecha? Tal vez.
  • ¿Tiene sentido restar un timedelta de un tiempo? Tal vez.

desarrollo a lo largo de las líneas de lo que tiene sentido:

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 

lo tanto, si se tratara de mí y yo estábamos diseñando una fecha, hora, DateTime, marco timedelta, que permitiría:

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

y para éstos:

date +/- timedelta 
time +/- timedelta 

me defecto a RETU del mismo tipo si el timedelta no tenía ninguno del otro tipo, y el aumento de una excepción si el timedelta tenía algo del otro tipo, pero habría una configuración que controlaría eso. El otro comportamiento posible sería eliminar la parte innecesaria, por lo que una fecha combinada con un timedelta que tuviera horas reduciría las horas y devolvería una fecha.

+0

Estoy de acuerdo con usted en eso. – jsbueno

+0

Alternativamente: Restar dos fechas tiene sentido: Sí Restar dos veces tiene sentido: Sí Restar una fecha y un momento tiene sentido: Tal vez –

+0

@MarkRibau: Muy buen punto. Deberías desarrollar eso un poco y convertirlo en una respuesta. –

0

Supongo que las cosas más importantes son la funcionalidad y la eficiencia. Por supuesto, usar un simple operador de + será más fácil de usar, pero no estoy seguro de la funcionalidad.

Si lo comparamos con datetime.combine, Lo combine hacer es:

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

Para DTM

  • Si dt es un objeto de fecha y tm es un objeto de tiempo, que fecha la información se toma de dt, tiempo información y tzinfo se toma de tm objeto
  • si dt es un objetode fecha y hora, el tiempo que su y se ignorará tzinfo atributos.

Desde ese punto de vista, el trabajo con datetime objetos no parecen ser simples objetos, sino estructuras más Compex con atributos diffrent, como información zona horaria.

Probablemente por eso los objetos datetime tienen algunas funciones adicionales que se utilizan para formatear el tipo de objeto y la estructura de datos del objeto.

Python tiene un lema (algo así):

en Python, nada es unchangable, si usted sabe lo que está haciendo. Si no, es mejor dejar las funciones de la biblioteca tal como están ...

Por lo tanto, en mi opinión, es mejor que utilice combine que la sobrecarga + operador

1

Debido a la existencia de los operadores de fecha, hora y adición de fecha y hora de tipo cruz y resta, yo creo que esto está bien, siempre y cuando esté bien definido.

Actualmente (2.7.2):

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

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

Creo que el siguiente también es razonable para una extensión:

timedelta = time - time 
datetime = date + time 

que iba a sugerir lo siguiente también, pero tiene muy time valores mínimos y máximos específicos para hour, minute, second y microsecond, lo que requiere un envolvente silencioso de los valores o la devolución de un tipo diferente:

time = time + timedelta 
time = time - timedelta 

Del mismo modo, date no se puede manejar un timedelta de menos de un día que se le agrega. A menudo me han dicho simplemente usar Duck Typing con Python, porque esa es la intención. Si eso es cierto, entonces yo propondría la siguiente interfaz completado:

[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 

En el que, dado el caso de que date tiene pérdida de precisión (por timedelta 's con días parciales), se promueve a datetime. Del mismo modo, dado el caso en el que time tiene una pérdida de precisión (para timedelta que arrojan un resultado de más de un día o un tiempo negativo), se promueve a timedelta. Sin embargo,, no me siento cómodo con [time|timedelta]. Tiene sentido dado el resto de la interfaz desde el paralelismo y las vistas de precisión, pero creo que podría ser más elegante simplemente envolver el tiempo a la hora correcta, cambiando así todas las [time|timedelta] a simplemente time, pero desafortunadamente eso nos deja con la precisión perdida.

1

En mi opinión, los usos más valiosos de la sobrecarga del operador son situaciones en las que se pueden combinar muchos valores de entrada. Usted nunca quiere tratar con:

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

o

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

Así que sobrecargue los símbolos matemáticos para crear una sintaxis más intuitiva. Otra forma de tratar este problema son las funciones variadas, como + en Scheme.

Con su date + time = datetime, que no tiene sentido para añadir datetime + datetime, datetime + time, o datetime + date, por lo que nunca podría encontrarse en una situación como los anteriores.

En mi opinión, una vez más, lo correcto es usar un método constructor. En un lenguaje con mecanografía fuerte como C++, tendrías DateTime(const Date &d, const Time &t). Con el tipado dinámico de Python, creo que dieron un nombre a la función, datetime.combine(date, time), para hacer que el código sea más claro cuando los tipos de las variables de entrada no son visibles en el código.