为什么我不能将datetime.date子类化?

时间:2008-12-29 23:08:19

标签: python oop datetime subclass

为什么以下工作不起作用(Python 2.5.2)?

>>> 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>

谢谢!

6 个答案:

答案 0 :(得分:35)

关于其他几个答案,这与用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)

答案 1 :(得分:10)

请阅读Data model上的Python参考资料,尤其是__new__ special method

摘录自该页面(我的斜体):

  

__new__()主要用于允许不可变类型的子类(如int,str或tuple)来自定义实例创建。它也通常在自定义元类中重写,以自定义类创建。

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
>>> 

答案 2 :(得分:4)

这是答案,可能的解决方案(使用函数或strptime而不是子类)

http://www.mail-archive.com/python-list@python.org/msg192783.html

答案 3 :(得分:2)

你的功能并没有被绕过; Python永远不会达到它所称的地步。由于datetime在C中实现,因此它在datetime.__new__而不是datetime.__init__中进行初始化。这是因为datetime是不可变的。你可以通过覆盖__new__代替__init__来解决这个问题。但正如其他人所建议的那样,最好的方法可能根本就不是继承日期时间。

答案 4 :(得分:0)

您应该使用工厂函数而不是创建子类:

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

答案 5 :(得分: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的属性。