我对这样的包有一个层次 struct :

test_script.py
package_name/
     __init__.py
     functionality_1.py
     functionality_2.py

出于测试目的,除了Functionality_1.py中的函数之外,还有一节将其作为Main运行.我用它来调试开发包的功能.Functionality_1.py的底部是一个标准的Main,如下所示:

if __name__ == "__main__":
     # Do some stuff

我希望从functionality_1.py中的函数记录使用记录器package_name.functionality_1,而functionality_2.py使用名为package_name.functionality_2的记录器

我try 了我在示例中看到的内容,使用

logger = logging.getLogger(__name__)

但是,如果我运行的是python -m package_name.functionality_1的Functionality_1.py文件,那么记录器总是被命名为__main__.

我不想硬编码记录器名称,但我不确定这样做的最好方法是什么.

您在哪里创建记录器,以便每个xxxx.py都有自己的记录器?__init__.py看起来确实是正确的位置.

在我的程序包文件中放一个main函数是不是不好?

推荐答案

在我的程序包文件中放一个main函数是不是不好?

对子模块来说,定义main函数不一定是坏事,但如果您希望记录器名称不是"__main__",那么您将希望避免执行子模块的值为top-level code.不要试图对抗或摆弄__main__的机器,这部分语言是僵化的,不太可能因为Guido considers executing submodules directly as scripts an anti-pattern而改变.

相反,您希望顶级代码环境是一个包装器脚本,它导入main并执行它.这样,logger = logging.getLogger(__name__)的正常模式将按预期工作,为您的子包创建适当的命名记录器层次 struct .日志(log)记录树层次 struct 很重要,以便可以递归地配置日志(log)记录处理程序,并且记录器可以传播到单个 node (即根记录器).

有一个名为Entry Points的Python打包特性,可用于自动生成这些包装器脚本.我将演示how to define them with setuptools,但现在所有其他主要构建系统都支持它们,因为它们是在PEP 621 – Storing project metadata in pyproject.toml年前指定的.

在您的子模块中,您将拥有类似于(简化)的内容:

# package_name/functionality_1.py
import logging

log = logging.getLogger(__name__)

def main():
    logging.basicConfig(format="%(name)s:%(message)s", level=logging.INFO)
    log.info("hello")

在您的pyproject.toml文件中,添加一个包含以下内容的部分:

[project.scripts]
functionality-1 = "package_name.functionality_1:main"
functionality-2 = "package_name.functionality_2:main"

安装程序(通常为pip)将自动生成包装脚本并将它们放在$路径上.这些脚本是您应该调用的,而不是直接作为__main__执行子模块,即,而不是使用:

python3 -m package_name.functionality_1
python3 -m package_name.functionality_2

您将拨打:

functionality-1
functionality-2

您可以从源代码中删除所有if __name__ == "__main__:个块,它们不是必需的.对于开发/测试,使用pip install -e .将包安装为editable(正是此安装命令将生成包装器脚本).

如果您愿意,可以查看包装器脚本的内容,看看它是如何工作的.你会在sysconfig.get_path("scripts")指定的位置找到它们.它们将设置可执行模式位,如果您在MacOS/Linux上,它们将有一个#!Shebang指向相应的Python环境(即用于安装的运行时).正是这些脚本作为顶级代码执行,它们只会从您的包代码中导入main函数(S)并调用它们.

Python相关问答推荐

为什么自定义pytree aux_data对于jnp.数组来说在.jit()之后跟踪,而对于np.数组来说则不是?

将C struct 的指针传递给Python中的ioctel

我可以使用极点优化这个面向cpu的pandas代码吗?

如何在telegram 机器人中发送音频?

阅读Polars Python中管道的函数定义

如何销毁框架并使其在tkinter中看起来像以前的样子?

如何计算列表列行之间的公共元素

我从带有langchain的mongoDB中的vector serch获得一个空数组

非常奇怪:tzLocal.get_Localzone()基于python3别名的不同输出?

无法通过python-jira访问jira工作日志(log)中的 comments

切片包括面具的第一个实例在内的眼镜的最佳方法是什么?

如何在Django基于类的视图中有效地使用UTE和RST HTIP方法?

删除字符串中第一次出现单词后的所有内容

实现自定义QWidgets作为QTimeEdit的弹出窗口

连接一个rabrame和另一个1d rabrame不是问题,但当使用[...]'运算符会产生不同的结果

当递归函数的返回值未绑定到变量时,非局部变量不更新:

Django RawSQL注释字段

无法连接到Keycloat服务器

如何在PySide/Qt QColumbnView中删除列

Geopandas未返回正确的缓冲区(单位:米)