我有延长内置日期时间一对夫妇类。*覆盖运营商+,使日期+时间=日期时间在Python
有没有什么好的理由不超载+(MyTime.__radd___
),所以指明MyDate +数值指明MyTime返回MyDateTime?
我有延长内置日期时间一对夫妇类。*覆盖运营商+,使日期+时间=日期时间在Python
有没有什么好的理由不超载+(MyTime.__radd___
),所以指明MyDate +数值指明MyTime返回MyDateTime?
这通常会令人不悦,因为你真的是合并而不是添加;这就是为什么实际的日期时间库有一个combine方法,而不是以这种方式使用添加。
我不知道Python中的任何其他情况,其中<instance of TypeA> + <instance of TypeB>
产生<instance of TypeC>
。因此,Principle of least astonishment建议您应该简单地提供一个combine
方法而不是超载加法。
有
这是已经实现为一个类的方法,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
是的,至少有一个很好的理由不来:结果实例是完全不同的两个输入实例。这很重要吗?我不这么认为 - 认为date - date
产量为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会减少时间并返回一个日期。
我同意你的意见。 – jsbueno 2012-01-10 21:32:38
或者: 减去两个日期是有道理的:是的 减去两次是有意义的:是的 减去日期和时间是有意义的:也许 – 2012-01-11 21:12:00
@MarkRibau:非常好的一点。你应该充实一点,并将其作为答案。 – 2012-01-11 21:17:52
我想最重要的是功能和效率。当然,使用简单的+
运算符将更易于使用,但我不确定功能。
如果我们把它比作datetime.combine
,什么combine
做的是:
dt = date(2011,01,01)
tm = time(20,00)
dtm = datetime.combine(dt, tm)
对于DTM
dt
是一个Date对象,并tm
是一个时间对象,比日期信息取自dt
,时间信息和tzinfo从tm
对象dt
是日期时间对象,比其时间和tzinfo属性将被忽略。从这个角度来看,与datetime
对象的工作似乎并不简单对象,但更COMPEX结构与不同势的属性,如时区信息。
可能这就是为什么datetime
对象有一些额外的功能,用于格式化对象的对象类型和数据结构。
的Python有一个座右铭(类似的东西):
在Python中,没有什么是unchangable,如果你知道自己在做什么。如果没有,最好留下图书馆功能,因为它们是...
所以,在我看来,最好是使用combine
是超载+
操作
由于日期,时间和日期时间十字型加法和减法运算符的存在,我认为这很好,只要它有明确的定义。
目前(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
,但不幸的是,这留下了我们失去了精确度。
在我看来,运算符重载最有价值的用途是许多输入值可以组合的情况。你永远要处理:
concat(concat(concat("Hello", ", "), concat("World", "!")), '\n');
或
distance = sqrt(add(add(x*x, y*y), z*z));
所以我们重载数学符号创造一个更加直观的语法。处理这个问题的另一种方法是可变参数函数,如Scheme中的+
。
随着您的date + time = datetime
,添加datetime + datetime
,datetime + time
或datetime + date
没有任何意义,所以你永远不会遇到上述情况。
在我看来,再一次,正确的做法是使用构造函数方法。在像C++这样具有强大类型的语言中,您将拥有DateTime(const Date &d, const Time &t)
。对于Python的动态类型,我想他们给函数一个名字datetime.combine(date, time)
,以便在代码中不可见输入变量的类型时使代码更清晰。
Haskell typeclass'Number'将'(+)'的算术运算符定义为'Number a => a - > a - > a'(即接受两个参数,类型是Number的一个实例并返回该类型)。有时候我希望有其他语言的操作符重载会施加这样的限制。在Python中,'+'是**加**或**连接**,没有别的。以完全不相关的方式超载它只会帮助......过度认为操作员超载的人是eeeevil。为此使用函数/方法有什么问题?!? – delnan 2010-11-08 20:43:32
@delnan:没有错,这个问题真的是关于重载有什么问题,以及为什么组合日期+时间与添加或并置相比是如此不同的操作。 – 2010-11-08 20:54:59
你可以在'MyDate'中添加'midnight'属性或方法(返回一个'MyDateTime'),也许可以将MyTime改为MyTimeSpan,然后再定义'__add__'会更有意义('mydatetime = mydate.midnight + mytimespan')。 – adw 2010-11-08 21:05:45