22

为什么以下不起作用(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>

谢谢!

4

6 回答 6

39

关于其他几个答案,这与 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)
于 2008-12-30T15:36:32.373 回答
11

请阅读有关数据模型的 Python 参考资料,尤其是有关__new__ 特殊方法的信息。

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

__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
>>> 
于 2008-12-31T01:19:50.620 回答
4

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

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

于 2008-12-29T23:12:44.887 回答
2

你的功能没有被绕过;Python 永远不会达到它会调用它的地步。由于 datetime 是在 C 中实现的,因此它在datetime.__new__not中进行初始化datetime.__init__。这是因为 datetime 是不可变的。您大概可以通过覆盖__new__而不是__init__. 但正如其他人所建议的那样,最好的方法可能根本不是子类化日期时间。

于 2008-12-30T02:50:29.800 回答
0

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

def first_day_of_the_year(year):
  return datetime.date(year, 1, 1)
于 2008-12-29T23:22:00.983 回答
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.dates 属性。

于 2008-12-30T07:21:29.907 回答