2010-11-08 78 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),以便在代碼中不可見輸入變量的類型時使代碼更清晰。