这两个调用之间有什么区别吗:
import logging
logging.getLogger().debug('test: %i' % 42)
和
logging.getLogger().debug('test: {}'.format(42))
假设当将 42
转换为字符串时,它被替换为一些长时间的计算(比如7.5百万年的计算),得到最终答案为42。
如果日志记录设置为调试模式,第一种方法是否进行了惰性求值?
他们都不是懒惰的。在发送到记录器之前,两个字符串都会被插值。Python日志记录中的惰性求值是使用单独的参数完成的。文档https://docs.python.org/2/library/logging.html建议如下进行字符串插值的惰性求值;
logging.getLogger().debug('test: %i', 42)
简述: 在这种情况下,我们发送了一个原始类型(字符串),但只有一个参数传递给记录器。因此它不能懒惰执行。
str.format
样式字符串进行惰性求值(lazy evaluation),尽管%
样式仍然是默认值。 - abarnert.debug('test: %i', takes_75_million_years_to_generate)
它只推迟了字符串本身的创建,而不是作为参数提供的值的生成,这在比较上是无关紧要的:}原始问题含糊不清,带有“我们假设42被一些长计算(例如750万年)替换,产生最终答案42。”的条件,但一旦42产生,成本已经付出了。 - user2864740我在评论中发布的参考文献中查找更详细的关于 %
和 .format()
的信息。
对于“惰性求值”的问题,答案是否。
只需进行简单的测试即可。
def func1(x):
time.sleep(5)
return(x)
def func2(x):
#time.sleep(5)
return(x)
%timeit 'debug1: %s' % func1(3)
5 s ± 1.31 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit 'debug2: {}'.format(func1(3))
5 s ± 1.45 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit 'debug1: %s' % func2(3)
297 ns ± 11.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit 'debug2: {}'.format(func2(3))
404 ns ± 4.56 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
.format
和%
的方法中,func()
总是会被计算。
logging
模块介入整个过程之前就已被Python完全评估。您可能想将格式化字符串及其参数作为单独的参数传递给.debug()
,以便它实际进行格式化 - 我假设仅在消息不会被过滤时才会执行此操作,但我不能百分之百确定。 - jasonharperif logging.getLogger().isEnabledFor(logging.DEBUG): …
。不过根据你对答案的评论,似乎你并不需要那个。 - abarnert