如何在Python中模拟“+”运算符(特别是datetime.date + datetime.timedelta)

4

我一直在解决Django中的日期模拟问题,现在遇到了最后一个(希望如此)困难的情况。我有一个FakeDate类,它派生自datetime.date,并进行模拟。

这个FakeDate类按预期工作,但是当我将datetime.timedelta添加到FakeDate时,它会返回真正的datetime.date,而不是模拟的日期。这很重要,因为第三方库中的其他地方有一个isinstance(value, datetime.date)检查,当使用timedelta时将始终失败。

>>> import mock
>>> import datetime
>>>
>>> class FakeDate(datetime.date):
...     @classmethod
...     def today(cls):
...         return cls(1999, 12, 31)
...
>>> FakeDate.today()
FakeDate(1999, 12, 31)
>>> FakeDate(2000, 1, 1)
FakeDate(2000, 1, 1)
>>> FakeDate(1999, 12, 31) + datetime.timedelta(days=1)
datetime.date(2000, 1, 1)

我希望FakeDate + timedelta的加法会返回一个FakeDate对象,而不是datetime.date对象 - 我想这涉及到对timedelta进行某种修补 - 但是我应该在哪里进行修补呢?

2个回答

4
FakeDate()类添加一个__add__方法:
class FakeDate(datetime.date):
     @classmethod
     def today(cls):
         return cls(1999, 12, 31)
     def __add__(self, other):
         res = super(FakeDate, self).__add__(other)
         return type(self)(res.year, res.month, res.day)

示例:

>>> class FakeDate(datetime.date):
...      @classmethod
...      def today(cls):
...          return cls(1999, 12, 31)
...      def __add__(self, other):
...          res = super(FakeDate, self).__add__(other)
...          return type(self)(res.year, res.month, res.day)
... 
>>> FakeDate.today() + datetime.timedelta(days=1)
FakeDate(2000, 1, 1)

请注意,您可以简单地将实际添加操作委托给datetime.date类;我们所需做的就是将结果转换回FakeDate()实例。

哇 - 我还在编辑问题!谢谢。一旦 SO 允许我,我会尽快接受答案。 - Hugo Rodger-Brown

1
你只需要在FakeDate类中定义一个__add__方法,这个方法控制了+操作符的行为。
import datetime

class FakeDate(datetime.date):
    @classmethod
    def today(cls):
        return cls(1999, 12, 31)

    def __add__(self, delta):
        # Create a datetime.date object so we don't need to do any calculations
        new_date = super(FakeDate, self).__add__(delta)
        # Then convert it to FakeDate.
        return FakeDate(new_date.year, new_date.month, new_date.day)

# Returns a FakeDate for 2000-01-01
FakeDate.today() + datetime.timedelta(days=1)

请注意,这仅适用于fakedate + timedelta的情况。如果你希望timedelta + fakedate也返回FakeDate的实例,你需要同样定义__radd__方法(与__add__相同的代码)。
有关与运算符相关的__magic_methods__更多信息,请参见http://docs.python.org/2/reference/datamodel.html#emulating-numeric-types

谢谢Max - 不幸的是Martijn先回答了,但我已经为你的答案点赞了(因为__radd__的评论非常有用)。 - Hugo Rodger-Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接