为什么 datetime.utcnow 的行为不像我对 freezegun 的预期那样?

我注意到一些我不明白的东西,我想知道是否有人可以阐明它。


简而言之:如果


x = datetime.datetime.utcnow


y = lambda: datetime.datetime.utcnow()

我希望x()并且y()总是表现得一样。然而,当 freezegun 参与时显然不是这种情况 - 它冻结y但没有x,我想知道为什么。(无论如何,如果x并且y在 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是一个绑定的类方法,但我不明白为什么这会暗示这种行为。


后记:time.time不这样做

查看utcnow()'s source它基本上只是一个包装器-time.time()但不要以这种方式发散...所以我猜这确实与绑定类方法有关-但我不知道是什么。time.timelambda: time.time() utcnow()


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


LEATH
浏览 91回答 1
1回答

牛魔王的故事

所以我猜这确实与 utcnow() 是一个绑定类方法有关——但我不知道是什么。看起来你的直觉是正确的。Freezegun 不会修补datetime类的单个方法 - 相反,它会用自己的类完全替换FakeDatetime该类。通过做作业:x = datetime.utcnowx 存储对原始utcnow()方法的引用,即使在freezegun.freeze_time()上下文管理器中也保持不变。另一方面,lambda: datetime.utcnow()调用当前上下文中可用的类utcnow(),并由.datetimeFakeDatetimefreezegun.freeze_time()time.time()由freezegunfake_time()修补。Freezegun 甚至搜索已加载的模块并修补存储对 的引用的变量time.time(),但它仅限于模块变量,因此它不会检查内部列表:import timeimport freezegunr = [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.0Time from list: 1571669871.8807676奖励:如果 freezegun 如此细致地查找time.time()存储在模块变量中的引用,为什么它不修补time.time()内部使用的datetime.utcnow()?在搜索sys.modules它时故意省略 datetime和模块不覆盖源函数,并且作为在模块中导入time的副作用保持不修补。time.timedatetime
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python