python - 为什么 datetime.utcnow 的行为与我对 freezegun 的预期不同?

标签 python datetime freezegun

我注意到一些我不明白的事情,我想知道是否有人可以解释一下。

简而言之:如果

  • x = datetime.datetime.utcnow

  • y = lambda: datetime.datetime.utcnow()

我希望 x()y() 的行为始终相同。然而,当 freezegun 参与时,情况显然并非如此 - 它卡住了 y 而不是 x,我想知道为什么。 (无论如何,如果 xy 是在 freezegun 上下文之外定义的,则这是正确的;在这样的上下文中,它们的行为似乎确实相同。)

示例:

from datetime import datetime
import freezegun

# I'd expect these two to behave the same, always.
x = datetime.utcnow
y = lambda: datetime.utcnow()

with freezegun.freeze_time('2019-01-02 03:04:05'):
    # Here their behaviours diverge
    print('Time from x:', x())
    print('Time from y:', y())

    # This behaves as I'd expect, however.
    z = datetime.utcnow
    print('Time from z:', z())))

结果:

Time from x: 2019-10-18 12:21:37.508590
Time from y: 2019-01-02 03:04:05
Time from z: 2019-01-02 03:04:05

这里Time from x是运行时的时间,即它不受freezegun的控制。

有人能解释一下吗?这只是 freezegun 的一些奇怪之处,或者当我假设 x 和 y 应该始终相等时,我是否误解了有关 python 的更基本的东西?我看到 utcnow 是一个绑定(bind)类方法,但我不明白为什么这会暗示这种行为。


后记:time.time 的行为并非如此

查看 utcnow()'s source它基本上只是 time.time() 的包装 - 但 time.timelambda: time.time() don' t 以这种方式发散...所以我猜测这确实utcnow() 作为绑定(bind)类方法有关 - 但我不知道不知道什么。

import time
import freezegun

r = time.time
s = lambda: time.time()

print('Time outside freezegun:', time.time())
with freezegun.freeze_time('2019-01-02 03:04:05'):
    print('Time from r:', r())
    print('Time from s:', s())

给出:

Time outside freezegun: 1571401765.2612312
Time from r: 1546398245.0
Time from s: 1546398245.0

正在播放的版本

$ python --version
Python 3.7.3

$ pip list | grep freezegun
freezegun               0.3.12

最佳答案

So I'm guessing this does have something to do with utcnow() being a bound class methiod — but I don't know what.

看来你的直觉是正确的。 Freezegun 不会修补 datetime 类的各个方法 - 相反 it replaces the class entirely具有自己的 FakeDatetime 类。

通过完成作业:

x = datetime.utcnow

x 存储对原始 utcnow() 方法的引用,即使在 freezegun.freeze_time() 上下文管理器中该方法也保持不变。

另一方面,lambda: datetime.utcnow() 在当前上下文中可用的 datetime 类上调用 utcnow(),并且这是由 freezegun.freeze_time() 修补的 FakeDatetime

time.time()patched by freezegun使用fake_time()。 Freezegun 甚至可以搜索已加载的模块和 patches variables存储对 time.time() 的引用,但它仅限于模块变量,例如它不检查内部列表:

import time
import freezegun

r = [time.time]

with freezegun.freeze_time('2019-01-02 03:04:05'):
    print('Time inside freezegun:', time.time())
    time_inside_list = r[0]
    print('Time from list:', time_inside_list())

输出:

Time inside freezegun: 1546398245.0
Time from list: 1571669871.8807676

奖励:如果 freezegun 如此细致地查找存储在模块变量中的 time.time() 引用,为什么它不修补 time.time( )datetime.utcnow() 内部使用?

sys.modules 中搜索时 deliberately omits datetimetime 模块不会覆盖源函数,并作为 time.time 导入到 datetime 模块中的副作用保持未修补。

关于python - 为什么 datetime.utcnow 的行为与我对 freezegun 的预期不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58451072/

相关文章:

python - 将 scrapy 蜘蛛构建到我自己的程序中,我不想从命令行调用 scrapy)

python - pandas:打印行中包含非零元素的列名称?

php - php 日期(格式化)函数的奇怪/不正确的输出

python - 如何在 Odoo 日期时间字段中显示不同的日期格式?

python - 如何卡住时间并断言模板中的时间戳?

python - SQLite 查询返回 false

python - 子集总和为 `itertools.combinations`

ruby-on-rails - 如何使用 Ruby on Rails 查找今天、昨天等的记录?

Python 数据类 : Mocking the default factory in a frozen Dataclass