我注意到一些我不明白的事情,我想知道是否有人可以解释一下。
简而言之:如果
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 是一个绑定(bind)类方法,但我不明白为什么这会暗示这种行为。
后记:time.time
的行为并非如此
查看 utcnow()
's source它基本上只是 time.time()
的包装 - 但 time.time
和 lambda: 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 datetime
和 time
模块不会覆盖源函数,并作为 time.time
导入到 datetime
模块中的副作用保持未修补。
关于python - 为什么 datetime.utcnow 的行为与我对 freezegun 的预期不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58451072/