PyLint消息:logging-format-interpolation

pfn*_*sel 128 python pylint python-3.x

对于以下代码:

logger.debug('message: {}'.format('test'))
Run Code Online (Sandbox Code Playgroud)

pylint 产生以下警告:

记录格式插值(W1202):

在日志记录函数中使用%格式并将%参数作为参数传递当日志语句的调用形式为"logging.(format_string.format(format_args ...))"时使用.此类调用应使用%格式,但通过将参数作为参数传递,将插值留给日志记录功能.

我知道我可以关掉这个警告,但我喜欢理解它.我假设使用format()是打印输出语句的首选方法pylint.为什么记录器语句不适用?

sth*_*ult 165

对于logger语句来说并不是这样,因为它依赖于像string这样的前"%"格式,使用给予记录器调用的额外参数来提供此字符串的延迟插值.例如,而不是做:

logger.error('oops caused by %s' % exc)
Run Code Online (Sandbox Code Playgroud)

你应该做

logger.error('oops caused by %s', exc)
Run Code Online (Sandbox Code Playgroud)

所以只有在实际发出消息时才会插入字符串.

使用时,您无法受益于此功能.format().


根据文档的优化部分logging:

消息参数的格式化将被推迟,直到无法避免.但是,计算传递给日志记录方法的参数也可能很昂贵,如果记录器只是丢弃您的事件,您可能希望避免这样做.

  • 但这是否意味着我们以后会遇到代码维护问题?我们以后会被pylint"推荐"在某个时候移动到`.format()`样式,因为`logging`已经升级了吗?我问,因为我对可维护性比对前沿速度性能更感兴趣,至少对于大多数任务而言. (22认同)
  • 是否有一个很好的参考,这个懒惰的评估是首选和有所作为?我在[PEP282](https://www.python.org/dev/peps/pep-0282/)或[日志库](https://docs.python.org/2/library)中找不到一个/logging.html) (9认同)
  • @pfnuesel,.format()在调用logger.error之前展开,而"延迟插值"意味着只在需要时才进行扩展(例如,消息实际显示在某处) (4认同)
  • 尽管警告背后的动机大多与性能有关(即:如果未发出日志语句,则可以节省内插成本),但值得注意的是,在许多(可以说是大多数)应用程序中,性能成本可以忽略不计。参见:https://github.com/PyCQA/pylint/issues/2395和https://github.com/PyCQA/pylint/issues/2354 (4认同)
  • @MikeWilliamson:我认为此消息是警告,因为可能存在副作用,但是您可以放心地忽略它。 (3认同)
  • PEP498 如何适合这里?它在懒惰的哪一边? (2认同)

mus*_*gok 49

也许这个时差可以帮助你。

以下描述不是您问题的答案,但可以帮助人们。

如果您想使用 fstrings(文字字符串插值)进行日志记录,那么您可以使用 将其从.pylintrc文件中禁用disable=logging-fstring-interpolation,请参阅:相关问题和评论

您也可以禁用logging-format-interpolation.


对于pylint 2.4:

.pylintrc文件中的日志样式有 3 个选项:old, new,fstr

fstr2.4 中添加并在2.5 中删除的选项

来自.pylintrc文件 (v2.4) 的描述:

[LOGGING]

# Format style used to check logging format string. `old` means using %
# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings.
logging-format-style=old
Run Code Online (Sandbox Code Playgroud)

对于旧的( logging-format-style=old):

foo = "bar"
self.logger.info("foo: %s", foo)
Run Code Online (Sandbox Code Playgroud)

对于新的( logging-format-style=new):

foo = "bar"
self.logger.info("foo: {}", foo)
# OR
self.logger.info("foo: {foo}", foo=foo)
Run Code Online (Sandbox Code Playgroud)

注意:即使您选择了选项,您也无法使用。.format()new

pylint 仍然对此代码给出相同的警告

self.logger.info("foo: {}".format(foo))  # W1202
# OR
self.logger.info("foo: {foo}".format(foo=foo))  # W1202
Run Code Online (Sandbox Code Playgroud)

对于fstr ( logging-format-style=fstr):

foo = "bar"
self.logger.info(f"foo: {foo}")
Run Code Online (Sandbox Code Playgroud)

就个人而言,我更喜欢 fstr 选项,因为PEP-0498

  • 您可以将 `"python.linting.pylintArgs": ["--logging-format-style=old"]` 添加到 vscode/settings.json 文件中。[文档](https://code.visualstudio.com/docs/python/linting#_pylint) (4认同)
  • 在 pylint 2.3.1 中: `optparse.OptionValueError: optionlogging-format-style: invalid value: 'fstr', should be in ['old', 'new']` 升级到最新的 pylint (2.4.4) 修复了这个问题。 (3认同)
  • 更新:删除了“fstr”日志格式选项,在“.pylintrc”中设置“disable=logging-fstring-interpolation”。https://github.com/PyCQA/pylint/issues/3570 (3认同)

Tri*_*ett 16

根据我的经验,比优化(对于大多数用例)延迟插值更令人信服的原因是它与 Sentry 等日志聚合器配合得很好。

考虑“用户登录”日志消息。如果您将用户插入到格式字符串中,您将拥有与用户一样多的不同日志消息。如果您像这样使用延迟插值,日志聚合器可以更合理地将其解释为具有一堆不同实例的相同日志消息。

  • 是的,这是惰性日志记录参数格式的最有力的论据 (2认同)

小智 7

下面的示例说明了为什么在日志记录中使用 %s 而不是 f 字符串更好。

>>> import logging
>>> logging.basicConfig(level=logging.INFO)
>>> logger = logging.getLogger('MyLogger')
>>>
>>> class MyClass:
...     def __init__(self, name: str) -> None:
...         self._name = name
...     def __str__(self) -> str:
...         print('GENERATING STRING')
...         return self._name
...
>>> c = MyClass('foo')
>>> logger.debug('Created: %s', c)
>>> logger.debug(f'Created: {c}')
GENERATING STRING
Run Code Online (Sandbox Code Playgroud)

受到Python 3.7 日志记录的启发:f-strings 与 %