gpt4 book ai didi

python - 使用 f 字符串样式格式规范记录 float (特别是 "msecs")时防止舍入(或至少长度溢出)

转载 作者:行者123 更新时间:2023-12-04 07:53:36 26 4
gpt4 key购买 nike

一点背景:
Python docs说:

In the case of {}-formatting, you can specify formatting flags by placing them after the attribute name, separated from it with a colon. For example: a placeholder of {msecs:03d} would format a millisecond value of 4 as 004.


但是,这不起作用,因为日志记录的 msecs值实际上是一个 float :
>>> record.msecs
275.38108825683594
所以尝试使用示例 {}文档中的格式引发了 ValueError :
>>> f'{record.msecs:03d}'
*** ValueError: Unknown format code 'd' for object of type 'float'
老式 % -用 03d 格式化适用于 float :
>>> '%03d' % record.msecs
'275'

基于上述发现,我使用了 float我的日志定义中的格式规范,如下所示:
logging.basicConfig(
level=logging.INFO,
format="{asctime}.{msecs:0>3.0f} [{levelname:.1s}] {message}",
datefmt="%Y-%m-%d %H:%M:%S",
style="{",
)
这似乎运行良好,直到我注意到这个日志条目:
2021-03-25 22:37:18.993 [I] ...
2021-03-25 22:37:18.997 [I] ...
2021-03-25 22:37:18.1000 [I] ...
2021-03-25 22:37:19.002 [I] ...
2021-03-25 22:37:19.004 [I] ...
这发生在日志记录的 msecs 时浮点值 >= 999.5:
>>> t1 = 999.499999
>>> t2 = 999.5
>>> print(f"{t1:0>3.0f} {t2:0>3.0f}")
999 1000
显然我更喜欢 .1000登录为 .000 (四舍五入而不溢出 3 位长度)如果有办法也增加 {asctime}时间戳的一部分。 但是我只要登录就可以了 .999 (截断到 int 而不是四舍五入)因为这种溢出只发生在很小的百分比时间,而且就我而言,这个日志记录并不是那么重要。
任何方法都可以做到这一点,除了回到旧式 % - 基于格式?

最佳答案

您可以覆盖 default millisecond format :

logging.basicConfig(
level=logging.INFO,
format="{asctime} ...{msecs:3.1f} ...{msecs:3.0f} [{levelname:.1s}] {message}",
# datefmt="%Y-%m-%d %H:%M:%S",
style="{",
)
logging.Formatter.default_msec_format = '%s.%03d'
我认为这达到了你想要的毫秒数被截断为三位数。不幸的是指定 datefmt搞砸了,毫秒不显示。

这里是定制 converterformatTime可用于替换默认 Formatter 方法的函数。这些将允许您在配置中指定 datefmt。它们一起工作,所以它们都必须被使用。
import logging

def converter(self,t):
'''Returns a tuple (time.struct_time, int)
'''

# separate seconds from fractional seconds
# round the fraction,
# adjust the seconds if needed
# turn the fraction into an integer
seconds = int(t)
msec = round(t - seconds,3)
if msec > .9995:
msec = 0
seconds += 1
else:
msec = int(1000 * msec)
# parts = list(time.localtime(seconds))
# parts[-2] = msec
t = time.localtime(seconds)
return t,msec

def formatTime(self, record, datefmt=None):
"""
Return the creation time of the specified LogRecord as formatted text.
This method should be called from format() by a formatter which
wants to make use of a formatted time. This method expects the
converter to return a (time.struct_time,int) tuple where the int is
between 0 and 999.
The int is the rounded msec of the record's creation time.
"""
ct,msec = self.converter(record.created)
if datefmt:
s = time.strftime(datefmt, ct)
else:
s = time.strftime(self.default_time_format, ct)
s = f'{s}.{msec:03d}'
return s

logging.basicConfig(
level=logging.INFO,
format="{asctime} | {message}",
datefmt="%Y-%m-%d %H:%M:%S",
style="{",
)

logging.Formatter.converter = converter
logging.Formatter.formatTime = formatTime
logging.info('foo')
该日志看起来像:
2021-03-27 16:12:05.498 | foo

如果 datefmt 参数不以秒结束,那么添加毫秒将是愚蠢的,所以也许应该检查一下。
def formatTime(self, record, datefmt=None):
"""
Return the creation time of the specified LogRecord as formatted text.
This method should be called from format() by a formatter which
wants to make use of a formatted time. This method expects the
converter to return a (time.struct_time,int) tuple where the int is
between 0 and 999.
The int is the rounded msec of the record's creation time.
"""
ct,msec = self.converter(record.created)
if datefmt:
s = time.strftime(datefmt, ct)
else:
s = time.strftime(self.default_time_format, ct)
# s = f'{s}.{msec:03d}'
# if self.default_msec_format:
# s = self.default_msec_format % (s, record.msecs)
if datefmt[-1] == 'S':
s = f'{s}.{msec:03d}'
return s

关于python - 使用 f 字符串样式格式规范记录 float (特别是 "msecs")时防止舍入(或至少长度溢出),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66820687/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com