使用“%”运算符的字符串格式的可选键?

Optional keys in string formats using '%' operator?

是否可以使用“%”运算符在 string formats 中添加可选键? 我正在使用 logging API 和 Python 2.7,所以我不能使用 Advanced String Formatting.

我的问题如下:

>>> import logging

>>> FORMAT = '%(asctime)-15s %(message)s %(user)s'
>>> logging.basicConfig(format=FORMAT)

>>> logging.warning("It works for:", extra={'user': 'me'})
2016-08-29 11:24:31,262 It works for: me

>>> logging.warning("It does't work!")
Traceback (most recent call last):
  ...
KeyError: 'user'
Logged from file <input>, line 1

如果 user 丢失,我想要一个空字符串。我该怎么做?

我试过 defaultdict,但失败了:

>>> import collections
>>> extra = collections.defaultdict(unicode)
>>> logging.warning("It does't work!", extra=extra)
Traceback (most recent call last):
  ...
KeyError: 'user'
Logged from file <input>, line 1

相比之下,使用Jinja2,我们可以做到:

>>> import jinja2
>>> jinja2.Template('name: {{ name }}, email: {{ email }}').render(name="me")
u'name: me, email: '

=> 这里也不例外,只是一个空字符串("email")。

A) defaultdict 方法工作正常,但前提是直接使用。

>>> import collections
>>> dd=collections.defaultdict(str)
>>> dd['k'] = 22
>>> '%(k)s %(nn)s' % dd
'22 '

B) 日志函数的 extra 参数按照文档中的描述使用,即不直接如上所示。这就是为什么使用 defaultdict 而不是常规 dict 并没有什么区别。

The third keyword argument is extra which can be used to pass a dictionary which is used to populate the dict of the LogRecord created for the logging event with user-defined attributes.


C) 您可以使用日志过滤器来处理丢失的额外数据:

import logging

class UserFilter:
    def filter(self, record):
        try:
            record.user
        except AttributeError:
            record.user = '<N/A>'
        return True

FORMAT = '%(asctime)-15s %(message)s %(user)s'
logging.basicConfig(format=FORMAT)
logging.getLogger().addFilter(UserFilter())

logging.warning("It works for:", extra={'user': 'me'})

logging.warning("It doesn't work!")
# DATE TIME It doesn't work! <N/A>

任何带有 filter 方法的 class 都可以。它可以就地修改记录,它必须 return True 接受记录或 False 过滤掉它。