2008-12-29 79 views
18

爲什麼以下工作(Python 2.5.2)?爲什麼我不能繼承datetime.date?

>>> import datetime 
>>> class D(datetime.date): 
     def __init__(self, year): 
      datetime.date.__init__(self, year, 1, 1) 
>>> D(2008) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: function takes exactly 3 arguments (1 given) 

我想創建一個類,簡直就像datetime.date,但有不同的__init__功能。顯然我的功能永遠不會被調用。相反,原來的datetime.date.__init__被調用並失敗,因爲它需要3個參數,而我正在傳入一個參數。

這是怎麼回事?這是一個線索?

>>> datetime.date.__init__ 
<slot wrapper '__init__' of 'object' objects> 

謝謝!

+0

另請參閱http://stackoverflow.com/questions/309 129 /爲什麼我不能繼承dict和異常在python – hop 2008-12-29 23:16:29

回答

34

關於其他幾個答案,這與C本身實施的日期沒有任何關係。 __init__方法什麼都不做,因爲它們是不可變的對象,因此構造函數(__new__)應該做所有的工作。你會看到相同的行爲子類INT,STR等

>>> import datetime 
>>> class D(datetime.date): 
     def __new__(cls, year): 
      return datetime.date.__new__(cls, year, 1, 1) 


>>> D(2008) 
D(2008, 1, 1) 
+0

我希望你不會介意我加了一點點強調 – tzot 2008-12-31 00:58:31

+0

好的答案,我之前對此確實不太清楚,但現在它變得非常有意義 – Kiv 2008-12-31 03:56:15

0

你應該使用一個工廠函數,而不是創建一個子類:

def first_day_of_the_year(year): 
    return datetime.date(year, 1, 1) 
+0

是的,這很酷,但我很好奇,爲什麼子類不工作(它是如何擴展類使差異),以及這是否可以克服... – Arkady 2008-12-29 23:25:04

2

你的功能沒有被繞過; Python只是從來沒有達到它稱之爲的地步。由於日期時間在C中實現,因此它在datetime.__new__而不是datetime.__init__中進行初始化。這是因爲日期時間是不可變的。你大概可以通過覆蓋__new__而不是__init__來解決這個問題。但正如其他人所建議的那樣,最好的方法可能根本不是繼承datetime。

+1

@Benjamin:請檢查我的答案,並考慮糾正你的,因爲這是迄今爲止投票最多的;基本上,只有你的最後一句話纔算有用。其他人誤解了/ ing。此外,請修復您的「它」→「它」和「(不」→「(注意」) – tzot 2008-12-31 01:24:17

0

你可以包裝它並添加擴展功能到你的包裝。

下面是一個例子:

class D2(object): 
    def __init__(self, *args, **kwargs): 
     self.date_object = datetime.date(*args, **kwargs) 

    def __getattr__(self, name): 
     return getattr(self.date_object, name) 

這裏是它如何工作的:

>>> d = D2(2005, 10, 20) 
>>> d.weekday() 
3 
>>> dir(d) 
['__class__', '__delattr__', '__dict__', '__doc__', '__getattr__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 
'__weakref__', 'date_object'] 
>>> d.strftime('%d.%m.%Y') 
'20.10.2005' 
>>> 

注意dir()沒有列出datetime.date小號屬性。

+0

@ΤΖΩΤΖΙΟΥ:你說得對,它實際上是可分類的,我會回到文檔並找出我製作的地方這個錯誤,同時我正在修復答案,謝謝 – muhuk 2008-12-31 07:26:10

10

請閱讀Data model Python的參考,特別是關於__new__special method。從該頁面

摘錄(我的斜體字):

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

datetime.datetime也是一個不變的類型。

PS如果你認爲:

  • 用C語言實現的對象不能被繼承,或
  • __init__不會被調用的C語言實現的對象,只有__new__

那麼請試試看:

>>> import array 
>>> array 
<module 'array' (built-in)> 
>>> class A(array.array): 
    def __init__(self, *args): 
     super(array.array, self).__init__(*args) 
     print "init is fine for objects implemented in C" 

>>> a=A('c') 
init is fine for objects implemented in C 
>>>