减少用于日志记录的样板文件
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
我阅读了 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
有了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