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

jan*_*jan 8 python datetime timedelta python-2.7

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

class Hours(datetime.timedelta):
    def __init__(self, hours):
        super(Hours, self).__init__(hours=hours)
Run Code Online (Sandbox Code Playgroud)

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

x = Hours(n)
Run Code Online (Sandbox Code Playgroud)

但是,上面的代码生成n天而不是n小时的timedelta.作为示例,请查看以下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
Run Code Online (Sandbox Code Playgroud)

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

unu*_*tbu 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)
Run Code Online (Sandbox Code Playgroud)

产量

10:00:00
Run Code Online (Sandbox Code Playgroud)

如果你覆盖__init__,但不是__new__,那么你的之前DT.timedelta.__new__调用.注意Hours.__init__

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

x = Hours(10)
Run Code Online (Sandbox Code Playgroud)

打印10 days, 0:00:00.这表明DT.timedelta.__new__在你有机会配置它之前已经将timedelta设置为10天Hours.__init__.

此外,DT.timedelta是不可变对象-你不能改变dayssecondsmicroseconds对象实例化后.Python通过使用该__new__方法创建不可变对象,并且通常不在该__init__方法中执行任何操作.可变对象执行相反的操作:它们配置对象__init__并且不执行任何操作__new__.


根据文档:

当子类化不可变的内置类型(如数字和字符串)时,偶尔在其他情况下,静态方法__new__会派上用场.__new__是实例构造的第一步,之前调用过__init__.__new__调用该方法时将类作为其第一个参数; 它的职责是返回该类的新实例.将此与__init__以下__init__内容进行比较:以实例作为其第一个参数进行调用,并且它不会返回任何内容; 它的职责是初始化实例....

所有这些都是这样做的,这样不可变类型可以在允许子类化的同时保留它们的不变性.

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


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

def hours(hours):
    return DT.timedelta(hours=hours)
Run Code Online (Sandbox Code Playgroud)