子类化datetime.timedelta时的奇怪行为

时间:2014-03-20 11:25:11

标签: python datetime python-2.7 timedelta

为方便起见,我想创建datetime.timedelta的子类。我们的想法是定义一个类:

class Hours(datetime.timedelta):
    def __init__(self, hours):
        super(Hours, self).__init__(hours=hours)

所以我可以快速创建这样的timedeltas:

x = Hours(n)

但是,上面的代码产生n天而不是n小时的时间值。举个例子,看看下面的ipython会话:

In [1]: import datetime

In [2]: class Hours(datetime.timedelta):
   ...:     def __init__(self, hours):
   ...:         super(Hours, self).__init__(hours=hours)
   ...:         

In [3]: print(Hours(10))
Out[3]: 10 days, 0:00:00

我无法解释这一点。有人吗?

1 个答案:

答案 0 :(得分:12)

如果您使用__new__,而不是__init__

import datetime as DT
class Hours(DT.timedelta):
    def __new__(self, hours):
        return DT.timedelta.__new__(self, hours=hours)
x = Hours(10)
print(x)

产量

10:00:00

如果您覆盖__init__,而不是__new__,那么DT.timedelta.__new__会在 Hours.__init__之前被称为。注意

import datetime as DT
class Hours(DT.timedelta):
    def __init__(self, hours):
        print(self)

x = Hours(10)

打印10 days, 0:00:00。这表明DT.timedelta.__new__已经将timedelta设置为10天,然后才有机会在Hours.__init__中配置它。

此外,DT.timedelta是一个不可变对象 - 在实例化对象后,您无法更改dayssecondsmicroseconds。 Python使用__new__方法创建不可变对象,通常不会在__init__方法中执行任何操作。可变对象反过来:它们在__init__中配置对象,而在__new__中不执行任何操作。


the docs

  

当继承不可变的内置类型(如数字和字符串)时,   偶尔在其他情况下,静态方法__new__会出现   派上用场。 __new__是实例构造的第一步,被调用   在__init__之前。以类为其调用__new__方法   第一个论点;它的责任是返回一个新的实例   类。将其与__init__进行比较:使用实例调用__init__   作为它的第一个论点,它不返回任何东西;它的   责任是初始化实例....

     

所有这一切都是为了使不可变类型可以保留它们   允许子类化的不变性。

(如果不可变对象在__init__中执行配置,那么你可以通过调用immutable.__init__来改变不可变。显然,我们不希望这样,所以immutable.__init__通常什么也不做。)


另请注意,除非您计划向Hours类添加新方法,否则它会更简单,因此更好地使用函数:

def hours(hours):
    return DT.timedelta(hours=hours)