2008-12-29 100 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 
>>> 
相关问题