文章来源于互联网(https://jq.qq.com/?_wv=1027&k=rX9CWKg4)

在Python中,被称为「程序的入口」的 if name ==‘main’: 总是出现在各种示例代码中,有一种流传广泛的错误观点是「这只是Python的一种编码习惯」。事实上程序的入口非常有用,绝非可有可无,例如在Python自带的多线程库要求必须把主进程写在 if入口内部才能正常运行。

直接写在Python最左端没有缩进的代码,在这个 *.py 文件被直接运行、或者被调用时会被执行,只有写在 if name ==‘main’: if入口内部才不会在被调用时执行。Python用这个简单的方法来判断当前的模块是被直接运行还是被调用,这是很重要的功能,如:

  • 我们可以把不想在被调用时执行的代码放在程序入口的if内部,比如自检程序。
  • 我们还把多线程的主线程写在程序入口的if内部。只能这么做,避免自己调用自己时重复执行主进程,下面会详细解释。

因此,初学Python时,直接把主程序写在不需要缩进的位置,完全不写 if name ==‘main’: 当然可以。一个既没有写一个被调用的库的能力,也不一定要学多进程的新手,很容易错误地认为「程序的入口」没什么用。

类似的,还有被少数人误解的还有 Python的文件头:

#!/bin/bash/python3  # 这一句话用来在代码被执行时,主动说明该选哪个路径下的编译器
#!/bin/bash/python2 # 例如这一句就选了Python2,不过2020年Python2快要完成过渡使命了

2020年底,我在写Python多进程教程时,没有搜索到合适的文章解释“程序的入口 if name ==‘main’: 与多线程的必要联系”,反而看到了很多高赞的片面回答。无奈之下只能自己写。对于少数有基础的人,下面讲程序入口与多线程部分也值得一看。

目录

  • 「程序的入口」是什么?
  • 程序入口与自检程序
  • 程序入口与多线程

更新日志

  • 第一版 2021-01-01 我会把评论区的好问题更新到正文里

「程序的入口」是什么?

用很短的话就能解释,我认可菜鸟分析↓的回答 ,部分高赞答案写得啰嗦

name 是当前模块名,当模块被直接运行时模块名为 main 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。

举例说明:当我在终端直接运行 python3 run1.py时,模块名被一律改为字符串__main__,当模块是被另一个 *.py程序导入(如在 *.py 中 import run1)而不是直接运行时,模块名是字符串run1。

在C语言和Java里也有类似的「程序入口」:


# Python的程序入口
if __name__ =='__main__': # 它对多进程非常重要
# 这里是主程序 # C语言的程序入口
void main(){
/* 这里是主程序 */
} # Java的程序入口
public static void main(String[] args){
// 这里是主程序
}

检验一下自己:下面的程序会print出什么东西?

# 新建一个名为【run1.py】的文件,填入下方代码
# 然后在终端输入【python3 run1.py】并运行 print(__name__, 'run1-outside') # 它会print出【__main__ run1-outside】
if __name__ =='__main__':
print(__name__, 'run1-inside') # 它会print出【__main__ run1-inside】

再检验一下自己:


# 新建另一个名为【run2.py】的文件,填入下方代码,并放在与【run1.py】的相同目录下,
# 然后在终端输入【python3 run2.py】并运行。用run2 调用run1 import run1 # 这一行代码调用了外部的代码 run1,它只会print出:
# 【run1 run1-outside】 # 它只print出这一行东西,并且run1.py的【__main__】变成了【run1】
# 【run1 run1-inside】 # 写在run1【if】缩进里的东西都没有被执行 print(__name__, 'run2-outside') # 它会print出【__main__ run2-outside】
if __name__ =='__main__':
print(__name__, 'run2-inside') # 它会print出【__main__ run2-inside】

程序入口与自检程序

当一个开发者编写一个库时(例如把它命名为 utils.py),如


# 这个库(模块)被命名为 utils.py
class C1:
...
def func1():
... c1 = C1() # 这是错误的做法,应该挪到 程序入口if内部
func1() # 这是错误的做法,应该挪到 程序入口if内部
if __name__ =='__main__':
c = C1()
func1()

当其他人只想调用 C1 或者 func1时,他在另一个Python文件中,用 import utils 导入 utils这个库时就不会运行程序入口if内部的任何代码了。

程序入口与多线程

实现多线程时,「程序入口」这个功能不可或缺。我需要同时运行多个 fun1,或者同时运行 fun1 fun2 … 如下:


def function1(id): # 这里是子进程
print(f'id {id}') def run__process(): # 这里是主进程
from multiprocessing import Process
process = [mp.Process(target=function1, args=(1,)),
mp.Process(target=function1, args=(2,)), ]
[p.start() for p in process] # 开启了两个进程
[p.join() for p in process] # 等待两个进程依次结束 # run__mp() # 主线程不建议写在 if外部。由于这里的例子很简单,你强行这么做可能不会报错
if __name__ =='__main__':
run__mp() # 正确做法:主线程只能写在 if内部

当我运行上面这个程序,它的【name ==‘main’】,因此它会执行 【if】内的代码。这些代码会创建新的多个子进程,自己调用自己。在被调用的子进程中,它的【name】 不等于【main】,因此它只会执行被主进程分配的任务(比如fun1),而不会像主进程一样通过「程序入口」再调用别的进程(行此僭越之事)。这是一个非常重要的功能,这里讲的不仅是Python,其他成熟的编程语言也能用相似的方法。

尽管有很多人点踩,但是这个分析是正确的。点踩的可能是其他原因引发了错误

尽管forkserver 依然不如 spawn更节省资源,但能解决问题也算不错了

由于我上面的例子过于简单(没有涉及进程通信、进程退出条件),如果你强行把主进程写在 if外部,也可能不会看到报错。这涉及很多因素,它与你使用的系统、子进程的创建方式(spwan、fork、forkserver、force=True/False)有关。我在这里只讲「程序的入口」,更多内容请移步
“ Compulsory usage of if name==“main” in windows while using multiprocessing - Stack Overflow ”
Tim Peters 与 David Heffernan 的回答都不错。

尽管Python的多进程已经做得挺不错了,希望随着以后版本的更新,多进程与「程序入口」的依赖关系应该能得到更好的解决。

使用PyTorch CUDA multiprocessing 的时候出现的错误 UserWarning: semaphore_tracker

(写于2021-03-03)

错误如下:


multiprocessing/semaphore_tracker.py:144:
UserWarning: semaphore_tracker: There appear to be 1 leaked semaphores to clean up at shutdown
len(cache)) Issue with multiprocessing semaphore tracking

相同问题描述:

解决方案:

即在运行 .py 文件前,使用以下语句修改环境参数,忽略这个Warning 带来的程序暂停

export PYTHONWARNINGS='ignore:semaphore_tracker:UserWarning'

等同于在 .py 文件内部使用:

os.environ['PYTHONWARNINGS'] = 'ignore:semaphore_tra

Python程序入口 __name__ == ‘__main__‘ 有重要功能(多线程)而非编程习惯的更多相关文章

  1. Python:if __name__ == '__main__'

    简介: __name__是当前模块名,当模块被直接运行时模块名为_main_,也就是当前的模块,当模块被导入时,模块名就不是__main__,即代码将不会执行. 关于代码if __name__ == ...

  2. python中if __name__ == '__main__'

    python 中__name__ = '__main__' 的作用,到底干嘛的? 有句话经典的概括了这段代码的意义: “Make a script both importable and execut ...

  3. python中if __name__ == '__main__': 解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ ==  '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一 ...

  4. python 中if __name__ = '__main__' 的作用

    python 中if __name__ = '__main__' 的作用 前言 首先我们要知道在python里面万物皆对象,模块也是对象,并且所有的模块都有一个内置属性 __name__. 一个模块的 ...

  5. python中if __name__ == '__main__': 的解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ ==  '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一 ...

  6. python基础之python中if __name__ == '__main__': 的解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

  7. 【python】if __name__ == '__main__'

    转载自:http://www.cnblogs.com/xuxm2007/archive/2010/08/04/1792463.html 当你打开一个.py文件时,经常会在代码的最下面看到if __na ...

  8. Python常见经典 python中if __name__ == '__main__': 的解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

  9. python中if __name__ == '__main__': 的解析(转载)

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

随机推荐

  1. for .. range中的坑

    最近在开发中使用了for range来遍历一个slice,结果在测试的时候遇到了bug,最后定位是错误使用for range造成的,这里记录一下: func redisSlaveScanBigKeys ...

  2. Java语言学习day20--7月26日

    ###11抽象类的产生 A:抽象类的产生 a:分析事物时,发现了共性内容,就出现向上抽取.会有这样一种特殊情况,就是方法功能声明相同,但方法功能主体不同.那么这时也可以抽取,但只抽取方法声明,不抽取方 ...

  3. 2021.11.10 P5231 [JSOI2012]玄武密码(AC自动机)

    2021.11.10 P5231 [JSOI2012]玄武密码(AC自动机) https://www.luogu.com.cn/problem/P5231 题意: 给出字符串S和若干T,求S与每个T的 ...

  4. golang内存对齐分析(转载)

    问题 type Part1 struct { a bool b int32 c int8 d int64 e byte } 在开始之前,希望你计算一下 Part1 共占用的大小是多少呢? func m ...

  5. Python 交互式解释器的二三事

    学 Python 不知道何时起成了一种风尚.这里,我也随便聊聊跟Python 的交互式解释器的几个有意思的小问题. 如何进入 Python 交互解释器? 当你安装好 Python 后,如何进入 Pyt ...

  6. 数据建模软件Chiner,颜值与实用性并存

    目录 一.chiner介绍 二.值得关注的功能点 2.1. 兼容各种格式的数据建模文件 2.2. 支持多数据库.代码生成 2.3. 支持逻辑视图与物理视图设计 2.4. 自动生成数据库文档 三.总结 ...

  7. 听说Integer有bug?1000不等于1000?

    bug? 前几天有位朋友找我,说:"老哥,老哥,我好像发现了Integer一个bug,你帮我看看什么情况?",说完给了我两个很简单的demo,上代码. 100 == 100 100 ...

  8. FreeRTOS --(0)简介

    转载自https://blog.csdn.net/zhoutaopower/article/details/106541595 FreeRTOS 是一个嵌入式实时操作系统,具有相对(相对 Linux. ...

  9. 程序员不得不知道的 API 接口常识

    说实话,我非常希望两年前刚准备找实习的自己能看到本篇文章,那个时候懵懵懂懂,跟着网上的免费教程做了一个购物商城就屁颠屁颠往简历上写. 至今我仍清晰地记得,那个电商教程是怎么定义接口的: 管它是增加.修 ...

  10. [笔记] 2-sat

    定义 简单的说就是给出 \(n\) 个集合,每个集合有两个元素,已知形如选 \(a\) 则必须选 \(b\) 的若干个条件, 问是否存在从每个集合选择一个元素满足条件的方案,通常可以题目只要求任意一种 ...