覆盖operator +以在Python中生成日期+时间=日期时间

时间:2010-11-08 20:33:26

标签: python operator-overloading

我有几个类扩展内置日期时间。*

有没有充分理由不重载+(MyTime.__radd___)所以MyDate + MyTime会返回MyDateTime?

6 个答案:

答案 0 :(得分: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

答案 1 :(得分:12)

这通常是不赞成的,因为你真的是在结合而不是加入;这就是为什么实际的日期时间库有一个combine方法而不是以这种方式使用添加。

我不知道Python中<instance of TypeA> + <instance of TypeB>产生<instance of TypeC>的任何其他情况。因此,Principle of least astonishment表示您应该只提供combine方法而不是重载添加。

答案 2 :(得分:4)

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

我看待它的方式:

  • 将两个日期加在一起是否有意义?否。
  • 两次加在一起有意义吗?否。
  • 一起添加日期和时间有意义吗?是啊!
  • 添加日期和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

所以,如果是我和我正在设计Date,Time,DateTime,TimeDelta框架,我会允许:

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

并为这些:

date +/- timedelta
time +/- timedelta

如果timedelta没有其他类型,我会默认返回相同的类型,如果timedelta确实有其他类型的某些类型,则会引发异常,但会有一个设置可以控制它。另一种可能的行为是删除不需要的部分 - 所以一个日期与一个有时间的timedelta相结合会减少时间并返回一个日期。

答案 3 :(得分: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具有hourminutesecond和{{1}的非常具体的最小值和最大值因此,需要静默环绕值或返回不同类型:

microsecond

同样地,time = time + timedelta time = time - timedelta 无法处理添加到其中的不到一天的date。通常我被告知只需使用Duck打字与Python ,因为这是意图。 如果确实如此,那么我建议使用以下完整的界面:

timedelta

其中,考虑到[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]更改为简单{{1但遗憾的是,这让我们失去了精确度。

答案 4 :(得分: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没有任何意义,因此您永远不会遇到上述情况。< / p>

在我看来,正确的方法是使用构造函数方法。在像C ++这样强类型的语言中,你有DateTime(const Date &d, const Time &t)。使用Python的动态类型,我猜他们给函数命名datetime.combine(date, time),以便在代码中看不到输入变量的类型时使代码更清晰。

答案 5 :(得分:0)

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

如果我们将其与datetime.combine进行比较,那么combine做的是:

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

dtm

  • 如果dt是日期对象且tm是时间对象,则 date 信息取自dt时间 info和 tzinfo 取自tm对象
  • 如果dt datetime 对象,则 time tzinfo 属性将被忽略。

从这个角度来看,使用datetime对象似乎不是简单的对象,而是具有不同属性的更复杂结构,例如时区信息

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

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

  

在python中,没有任何东西是不可改变的,如果你知道自己在做什么。如果没有,最好保留库函数......

因此,在我看来,最好使用combine重载+运算符