Python 脚本一个要注意的点

简介: Python 脚本一个要注意的点

我发现有不少朋友写 Python 脚本非常随意,要么不用函数,要么函数随处定义,反正第一眼看不出要执行的第一行代码位于何处,这样的脚本可读性很差,而且容易隐藏 bug,解决这个问题很简单,当我们写 Python 脚本时,一定要加上这个:

defmain():
   # do something
   print("do something.")


if __name__ == "__main__":
   main()

你可能要反对了:我怎么爽就怎么写,凭什么听你的,多写个 if __name__...?

别急,让我说三个原因。

第一,它让 Python 文件的作用更加明确

首先需要明白 __name__ 的作用,当脚本直接被 Python 解释器执行时,其值就是 "__main__",当其被其他 Python 程序 import 的时候,其值就是对应的 Python 脚本文件名,可以在 Python 解释器验证下,假定有个 some_script.py 其内容如下:

print("some_script.py")
print(__name__)

在 Python 解释器导入一下:

❯ vim some_script.py
❯ python
Python 3.8.5 (v3.8.5:580fbb018f, Jul 202020, 12:11:27)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits"or"license"for more information.
>>> import some_script
some_script.py
some_script
>>>

可以看到,__name__ 的值就是 Python 脚本的文件名 some_script。

也就是说 if __name__ == "__main__": 后面的代码在 import 的时候是不会运行的。

明白了这一点,if __name__ == "__main__": 就可以做为区分脚本和库的一个标志,当我们看到 if __name__ == "__main__": 时,就认为这一个可以直接运行的脚本,当没有看到这行代码时,就认为这是一个库,可以被其他程序引用,Explicit is better than implicit.,不是吗?

再举个例子:

假如你写了一个不带if __name__ == "__main__": 的脚本,叫 bad_script.py,内容如下:

defuseful_function(x):
   return x * x


classUsefulClass:
   def__init__(self, x):
       self.x = x

#你自己测试了一吧,没毛病
for i in range(7):
   print(useful_function(i))

别人写了个 useful.py,引用了你的 useful_function:

from bad_script import useful_function


defmain():
   print(f'{useful_function(3)=}')


if __name__ == '__main__':
   main()

一运行,发现打印了不可预期的内容

查了半天原因,发现是你的脚本输出的,你说别人会不会骂你?

假如你在自己脚本里定义了全局变量,别人如果在不合适的位置导入了 *,就会把你这个全局变量也导入,导致变量覆盖,很容易会出现 bug。

第二,它让 Python 文件更加易读,对 IDE 友好

有了 if __name__ == "__main__": 相当于 Python 程序也有了一个入口函数,所有的变量都从这里开始定义和使用,我们可以清晰的知道程序的逻辑开始于何处(当然还需要我们自觉的把程序的开始逻辑都放在这里)

其实,这也是 PyCharm 推荐的做法,当你新建一个项目的时候,它默认创建的 main.py 就是长这样的:

image.png

if __name__ == "__main__": 的那一行的最左边也有一个绿色的运行按钮,点击一下,程序就从这一行开始运行了。

为什么很多优秀的编程语言,比如 C、Java、Golang、C++ 都有一个 main 入口函数呢?我想很重要的一个原因就是就是程序入口统一,容易阅读。

第三、多进程场景下,必须用 if main

比如说你用多进程搞并行计算,写了这样的代码:

import multiprocessing as mp


defuseful_function(x):
   return x * x

print("processing in parallel")
with mp.Pool() as p:
   results = p.map(useful_function, [1, 2, 3, 4])
   print(results)

当你运行的时候,会发现程序不停的在创建进程,同时也在不停的报错 RuntimeError,即使你 Ctrl C 也无法终止程序。而加上了 if __name__ == "__main__": 程序就会按照预期的进行:

import multiprocessing as mp


defuseful_function(x):
   return x * x

if __name__ == '__main__':
   print("processing in parallel")
   with mp.Pool() as p:
       results = p.map(useful_function, [1, 2, 3, 4])
       print(results)

这是为什么呢?

其实我是这样理解的,Python 的多程序就是启动了多个 Python 解释器,每个 Python 解释器都会导入你这个脚本,复制一份全局变量和函数给子进程用,如果有了if __name__ == "__main__":,那它后面的代码就不会被 import,也就不会被重复执行。否则,这个创建多进程的代码就会被 import,就会被执行,从而无限递归的去创建子进程,Python3 会报 RuntimeError,顺序是先创建进程,然后报错的,因此就会出现不停的创建进程,不停的报错,Ctrl C 也无法终止的现象,只能 kill 掉整个终端。这里有个官方解释[1]

最后的话

if __name__ == "__main__": 虽然不是强制的,但是基于上述三点原因,我强烈推荐你这么做,它是 Python 社区的约定,对应Python 之禅:明确优于隐晦。正如 _ 作为变量名的意思就是告诉读代码的人:这个变量不重要,后面也不会用到它。当你看到 Python 脚本有 if __name__ == "__main__": 时,就会意识到,这是一个可执行的脚本,当被其他程序导入时,这部分代码不会被执行,而多进程的程序中,这是必须的。

参考资料

官方解释:

https://docs.python.org/zh-cn/3/library/multiprocessing.html#programming-guidelines

相关文章
|
2月前
|
安全 网络安全 文件存储
思科设备巡检命令Python脚本大集合
【10月更文挑战第18天】
84 1
思科设备巡检命令Python脚本大集合
|
17天前
|
数据采集 监控 数据挖掘
Python自动化脚本:高效办公新助手###
本文将带你走进Python自动化脚本的奇妙世界,探索其在提升办公效率中的强大潜力。随着信息技术的飞速发展,重复性工作逐渐被自动化工具取代。Python作为一门简洁而强大的编程语言,凭借其丰富的库支持和易学易用的特点,成为编写自动化脚本的首选。无论是数据处理、文件管理还是网页爬虫,Python都能游刃有余地完成任务,极大地减轻了人工操作的负担。接下来,让我们一起领略Python自动化脚本的魅力,开启高效办公的新篇章。 ###
|
3天前
|
数据采集 存储 监控
21个Python脚本自动执行日常任务(2)
21个Python脚本自动执行日常任务(2)
28 7
21个Python脚本自动执行日常任务(2)
|
1月前
|
关系型数据库 MySQL 数据库连接
python脚本:连接数据库,检查直播流是否可用
【10月更文挑战第13天】本脚本使用 `mysql-connector-python` 连接MySQL数据库,检查 `live_streams` 表中每个直播流URL的可用性。通过 `requests` 库发送HTTP请求,输出每个URL的检查结果。需安装 `mysql-connector-python` 和 `requests` 库,并配置数据库连接参数。
128 68
|
10天前
|
Android开发 开发者 Python
通过标签清理微信好友:Python自动化脚本解析
微信已成为日常生活中的重要社交工具,但随着使用时间增长,好友列表可能变得臃肿。本文介绍了一个基于 Python 的自动化脚本,利用 `uiautomator2` 库,通过模拟用户操作实现根据标签批量清理微信好友的功能。脚本包括环境准备、类定义、方法实现等部分,详细解析了如何通过标签筛选并删除好友,适合需要批量管理微信好友的用户。
21 7
|
15天前
|
监控 数据挖掘 数据安全/隐私保护
Python脚本:自动化下载视频的日志记录
Python脚本:自动化下载视频的日志记录
|
20天前
|
运维 监控 网络安全
自动化运维的崛起:如何利用Python脚本简化日常任务
【10月更文挑战第43天】在数字化时代的浪潮中,运维工作已从繁琐的手工操作转变为高效的自动化流程。本文将引导您了解如何运用Python编写脚本,以实现日常运维任务的自动化,从而提升工作效率和准确性。我们将通过一个实际案例,展示如何使用Python来自动部署应用、监控服务器状态并生成报告。文章不仅适合运维新手入门,也能为有经验的运维工程师提供新的视角和灵感。
|
25天前
|
存储 Python
Python自动化脚本编写指南
【10月更文挑战第38天】本文旨在为初学者提供一条清晰的路径,通过Python实现日常任务的自动化。我们将从基础语法讲起,逐步引导读者理解如何将代码块组合成有效脚本,并探讨常见错误及调试技巧。文章不仅涉及理论知识,还包括实际案例分析,帮助读者快速入门并提升编程能力。
57 2
|
27天前
|
运维 监控 Python
自动化运维:使用Python脚本简化日常任务
【10月更文挑战第36天】在数字化时代,运维工作的效率和准确性成为企业竞争力的关键。本文将介绍如何通过编写Python脚本来自动化日常的运维任务,不仅提高工作效率,还能降低人为错误的风险。从基础的文件操作到进阶的网络管理,我们将一步步展示Python在自动化运维中的应用,并分享实用的代码示例,帮助读者快速掌握自动化运维的核心技能。
65 3
|
1月前
|
缓存 运维 NoSQL
python常见运维脚本_Python运维常用脚本
python常见运维脚本_Python运维常用脚本
30 3