减少用于日志记录的样板文件

Reduce boilerplate for logging

我阅读了 structlog 的文档:Configuration

The goal is to reduce your per-file logging boilerplate to:

from structlog import get_logger
logger = get_logger()

有没有办法将其减少到 一个 导入行(没有 ;)?

无法在导入语句内执行调用。

来自 Python's grammar:

import_stmt: import_name | import_from
import_name: 'import' dotted_as_names
import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
              'import' ('*' | '(' import_as_names ')' | import_as_names))
import_as_name: NAME ['as' NAME]
dotted_as_name: dotted_name ['as' NAME]
import_as_names: import_as_name (',' import_as_name)* [',']
dotted_as_names: dotted_as_name (',' dotted_as_name)*
dotted_name: NAME ('.' NAME)*

语法没有指定可以调用的导入语句的形式。特别是,唯一接受括号的形式是 '(' import_as_names ')',其中 import_as_names 定义为 NAME ['as' NAME],而函数调用需要使用 parameters.

我建议通读语法规范以获得 in-depth 理解。


但是,您可以在一行中完成您的目标。以下是三种解决方案。

第一个是你在问题中提到的。第二个是由 Chris_Rands in comments (and later on in ) 引起的。第三个基本上是作弊,看起来像主文件中的 one-liner。

有了semi-colon

from structlog import get_logger; logger = get_logger()

通过调用底层 __import__ 函数

logger = __import__('structlog').get_logger()

请注意,这 不是 导入语句,因为它不匹配上述摘要的任何指定形式。

通过使用中间文件

interface.py

from structlog import get_logger
logger = get_logger()

main.py

from interface import logger

这更像是作弊,但从主文件的角度来看,导入是单行的。

如果您选择此方法,我强烈建议为 interface.py 创建一个新文件。您可能想在 structlog.py 的末尾添加一个 logger = get_logger(),但您可能会破坏模块,最明显的情况是某些名为 logger 的变量已经存在。


也就是说,将代码分成两行绝对没问题。我知道人们可能希望尽可能多地制作 one-liners,因为 Python 非常擅长(我不会 link 关于 lambda 表达式的帖子,但你可以很容易地找到一些例子)。

然而,get_logger 实际上被引用为 structlog.get_logger(*args, **kwargs),这意味着它可以接收参数来初始化记录器 returns。 get_logger's source.

中记录了它们的使用方式

现在,假设您必须执行一些处理来生成这些参数。您的代码将类似于:

from structlog import get_logger

args = initialize_args()
kwargs = initialize_kwargs()

logger = get_logger(args, kwargs)

好吧,你仍然可以把它变成 one-liner...但是它会变得不必要地长,而且几乎不可读。

正如我在评论中提到的,要获得一个衬垫,您可以使用 __import__():

logger = __import__('structlog').get_logger()

但是,如 documentation 中所述,通常不建议使用 __import__()

Direct use of __import__() is also discouraged in favor of importlib.import_module().

importlib.import_module() 需要导入自身,通过 import importlib 添加另一行,除非你通过 __import__() 导入 importlib,这似乎是个坏主意。

无论如何,在您的情况下不需要 __import__()importlib.import_module(),它们通常在您从将模块名称存储为字符串的变量动态导入时使用。我认为您应该保留现有的两行,在我看来它们简洁易读。

正如其他人所说,没有一种干净的方法可以在同一行上进行导入和函数调用。但是,可能有不同的方法来解决这个问题。

我假设您想执行 DRY 原则。如果是这种情况,您可以在代码库中放置一个小文件来执行以下操作:

# mylog.py
from structlog import get_logger
logger = get_logger() # or any other logic to get a compatible logger

现在,在所有其他地方你可以直接获取记录器实例:

from mylog import logger