2010-11-08 123 views
7

我有延长内置日期时间一对夫妇类。*覆盖运营商+,使日期+时间=日期时间在Python

有没有什么好的理由不超载+(MyTime.__radd___),所以指明MyDate +数值指明MyTime返回MyDateTime?

+0

Haskell typeclass'Number'将'(+)'的算术运算符定义为'Number a => a - > a - > a'(即接受两个参数,类型是Number的一个实例并返回该类型)。有时候我希望有其他语言的操作符重载会施加这样的限制。在Python中,'+'是**加**或**连接**,没有别的。以完全不相关的方式超载它只会帮助......过度认为操作员超载的人是eeeevil。为此使用函数/方法有什么问题?!? – delnan 2010-11-08 20:43:32

+1

@delnan:没有错,这个问题真的是关于重载有什么问题,以及为什么组合日期+时间与添加或并置相比是如此不同的操作。 – 2010-11-08 20:54:59

+1

你可以在'MyDate'中添加'midnight'属性或方法(返回一个'MyDateTime'),也许可以将MyTime改为MyTimeSpan,然后再定义'__add__'会更有意义('mydatetime = mydate.midnight + mytimespan')。 – adw 2010-11-08 21:05:45

回答

12

这通常会令人不悦,因为你真的是合并而不是添加;这就是为什么实际的日期时间库有一个combine方法,而不是以这种方式使用添加。

我不知道Python中的任何其他情况,其中<instance of TypeA> + <instance of TypeB>产生<instance of TypeC>。因此,Principle of least astonishment建议您应该简单地提供一个combine方法而不是超载加法。

+5

- '产生'的实例'的例子。例如采取'timedelta = datetime1 - datetime2'。 – 2012-01-12 03:48:23

16

这是已经实现为一个类的方法,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 
4

是的,至少有一个很好的理由不来:结果实例是完全不同的两个输入实例。这很重要吗?我不这么认为 - 认为date - date产量为timedelta

我看到它的方式:

  • 是否加两个日期一起有意义吗?
  • 增加两次是否合理?
  • 增加日期和时间在一起是否有意义?对!
  • 添加日期和时间点togethor是否有意义?也许。
  • 添加时间和timedelta在一起是否有意义?也许。

和减法

  • 是否减去两个日期有意义吗?是。
  • 减两次是否有意义?是。
  • 从日期减去时间是否合理?不。
  • 从日期中减去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 

所以,如果是我的话,我设计一个日期,时间,日期时间,TimeDelta框架,我会允许:

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

,并为这些:

date +/- timedelta 
time +/- timedelta 

我将默认为换货政...如果timedelta没有其他类型,则会生成相同的类型,如果timedelta确实有其他类型的异常,则会引发异常,但会有一个设置来控制该类型。另一种可能的行为是放弃不需要的部分 - 所以一个日期加上一个有几小时的timedelta会减少时间并返回一个日期。

+0

我同意你的意见。 – jsbueno 2012-01-10 21:32:38

+0

或者: 减去两个日期是有道理的:是的 减去两次是有意义的:是的 减去日期和时间是有意义的:也许 – 2012-01-11 21:12:00

+0

@MarkRibau:非常好的一点。你应该充实一点,并将其作为答案。 – 2012-01-11 21:17:52

0

我想最重要的是功能和效率。当然,使用简单的+运算符将更易于使用,但我不确定功能。

如果我们把它比作datetime.combine,什么combine做的是:

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

对于DTM

  • 如果dt是一个Date对象,并tm是一个时间对象,比日期信息取自dt,时间信息和tzinfotm对象
  • 采取如果dt日期时间对象,比其时间tzinfo属性将被忽略。

从这个角度来看,与datetime对象的工作似乎并不简单对象,但更COMPEX结构与不同势的属性,如时区信息

可能这就是为什么datetime对象有一些额外的功能,用于格式化对象的对象类型和数据结构。

的Python有一个座右铭(类似的东西):

在Python中,没有什么是unchangable,如果你知道自己在做什么。如果没有,最好留下图书馆功能,因为它们是...

所以,在我看来,最好是使用combine是超载+操作

1

由于日期,时间和日期时间十字型加法和减法运算符的存在,我认为这很好,只要它有明确的定义。

目前(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,secondmicrosecond的特定最小值和最大值,因此需要对数值进行静态回绕或返回不同类型:

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,但不幸的是,这留下了我们失去了精确度。

1

在我看来,运算符重载最有价值的用途是许多输入值可以组合的情况。你永远要处理:

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

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

所以我们重载数学符号创造一个更加直观的语法。处理这个问题的另一种方法是可变参数函数,如Scheme中的+

随着您的date + time = datetime,添加datetime + datetimedatetime + timedatetime + date没有任何意义,所以你永远不会遇到上述情况。

在我看来,再一次,正确的做法是使用构造函数方法。在像C++这样具有强大类型的语言中,您将拥有DateTime(const Date &d, const Time &t)。对于Python的动态类型,我想他们给函数一个名字datetime.combine(date, time),以便在代码中不可见输入变量的类型时使代码更清晰。