Python面试|一文让你读懂if __name__==’__main__’的含义

程序入口

对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# 等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C 和 C++ 都需要有一个 main 函数来作为程序的入口,也就是程序的运行会从 main 函数开始。同样,Java 和 C# 必须要有一个包含 Main 方法的主类来作为程序入口。

而 Python 则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。

一个 Python 源码文件除了可以被直接运行外,还可以作为模块(也就是库)被导入。不管是导入还是直接运行,最顶层的代码都会被运行(Python 用缩进来区分代码层次)。而实际上在导入的时候,有一部分代码我们是不希望被运行的。

举一个例子来说明一下,假设我们有一个 const.py 文件,内容如下:

PI = 3.14def main():
 print "PI:", PI
main()

我们在这个文件里边定义了一些常量,然后又写了一个 main 函数来输出定义的常量,最后运行 main 函数就相当于对定义做一遍人工检查,看看值设置的都对不对。然后我们直接执行该文件(python const.py),输出:

PI: 3.14

现在,我们有一个 area.py 文件,用于计算圆的面积,该文件里边需要用到 const.py 文件中的 PI 变量,那么我们从 const.py 中把 PI 变量导入到 area.py 中:

from const import PIdef calc_round_area(radius):
 return PI * (radius ** 2)def main():
 print "round area: ", calc_round_area(2)
main()

运行 area.py,输出结果:

PI: 3.14round area: 12.56

可以看到,const 中的 main 函数也被运行了,实际上我们是不希望它被运行,提供 main 也只是为了对常量定义进行下测试。这时,if name == ‘ main ‘ 就派上了用场。把 const.py 改一下:

PI = 3.14def main():
 print "PI:", PIif __name__ == "__main__":
 main()

然后再运行 area.py,输出如下:

round area: 12.56

再运行下 const.py,输出如下:

PI: 3.14

这才是我们想要的效果。

if name == ‘ main ‘ 就相当于是 Python 模拟的程序入口。Python 本身并没有规定这么写,这只是一种编码习惯。由于模块之间相互引用,不同模块可能都有这样的定义,而入口程序只能有一个。到底哪个入口程序被选中,这取决于 name 的值。

name

name 是内置变量,用于表示当前模块的名字,同时还能反映一个包的结构。来举个例子,假设有如下一个包:

a├── b│ ├── c.py│ └── __init__.py└── __init__.py

目录中所有 py 文件的内容都为:

print(__name__)

我们执行 python -c “import a.b.c”,输出结果:

aa.ba.b.c

由此可见, name 可以清晰的反映一个模块在包中的层次。其实,所谓模块名就是 import 时需要用到的名字,例如:

import tornadoimport tornado.web

这里的 tornado 和 tornado.web 就被称为模块的模块名。

如果一个模块被直接运行,则其没有包结构,其 name 值为 main 。例如在上例中,我们直接运行 c.py 文件(python a/b/c.py),输出结果如下:

__main__

所以,if name == ‘ main ‘ 我们简单的理解就是: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行。

实际上,这个问题还可以衍生出其他的一些知识点,例如 main .py 文件与 Python 的 -m 参数。

main.py 文件与 python -m

Python 的 -m 参数用于将一个模块或者包作为一个脚本运行,而 main .py 文件则相当于是一个包的”入口程序“。

首先我们需要来看看 python xxx.py 与 python -m xxx.py 的区别。两种运行 Python 程序的方式的不同点在于,一种是直接运行,一种是当做模块来运行。

先来看一个简单的例子,假设有一个 Python 文件 run.py,其内容如下:

import sys
print(sys.path)

我们用直接运行的方式启动(python run.py),输出结果(为了说明问题,输出结果只截取了重要部分,下同):

['/home/huoty/aboutme/pythonstudy/main', ...]

然后以模块的方式运行(python -m run.py):

['', ...]
/usr/bin/python: No module named run.py

由于输出结果只列出了关键的部分,应该很容易看出他们之间的差异。直接运行是把 run.py 文件所在的目录放到了 sys.path 属性中。以模块方式运行是把你输入命令的目录(也就是当前工作路径),放到了 sys.path 属性中。以模块方式运行还有一个不同的地方是,多出了一行 No module named run.py 的错误。实际上以模块方式运行时,Python 先对 run.py 执行一遍 import,所以 print sys.path 被成功执行,然后 Python 才尝试运行 run.py 模块,但是,在 path 变量中并没有 run.py 这个模块,所以报错。而正确的运行方式,应该是 python -m run.

这个例子并不能明显的说明问题。接着我们来看看 main .py 的作用。

仍然先看例子,有如下一个包:

package
├── __init__.py
└── __main__.py
init.pyimport sys
print("__init__")
print(sys.path)
main.pyimport sys
print("__main__")
print(sys.path)

用 python -m package 运行结果:

__init__
['', ...]
__main__
['', ...]

用 python package 运行结果:

__main__
['package', ...]

然后我们来总结一下:

1、 加上 -m 参数时会把当前工作目录添加到 sys.path 中,而不加时则会把脚本所在目录添加到 sys.path 中。 
2、 加上 -m 参数时 Python 会先将模块或者包导入,然后再执行 
3、 main.py 文件是一个包或者目录的入口程序。不管是用 python package 还是用 python -m package 运行时,main.py 文件总是被执行。 
后序

我试图使用长篇大论来阐述,在 Python 中如何理解 if name == ‘ main ‘ 这个问题,不知道我有没有描述得足够的明白。Python 的确是简单的,优雅的,但也有很多问题是不太容易理解的,例如很多高级的特性,像元类、生成器表达式、描述符、协程等。Python 并没有在太多的地方规定要如何如何,很多的用法只是惯用法,例如 self 和本文讨论的内容。这些用法或是为了让代码看起来更优雅,或是前人的经验。使用 Python 是有无限可能的,你可以写出很多简洁优雅的代码。

Image placeholder
YISU_ZHICHENG
未设置
  65人点赞

没有讨论,发表一下自己的看法吧

推荐文章
Python教程-一文读懂运算和运算符

Python支持多种运算符,下表按照优先级从高到低的顺序列出了所有的运算符,运算符的优先级指的是多个运算符同时出现时,先做什么运算然后再做什么运算。 [][:] 下标,切片 ** 指数 ~+- 按

一文读懂数据库70年发展史

作者:常垒资本 冯斯基顾问:云和恩墨、戴工玖、周家晶零1949-19791956年,周恩来总理亲自领导了“科学技术发展十二年规划”,标志着我国计算机事业的开始。而那时,几乎没有人知道计算技术是怎么回事

一文读懂HBase多租户

本文从三个方面介绍了HBase的多租户实现。上篇文章回顾:HDFS短路读详解多租户(multi-tenancytechnology),参考维基百科定义,它是在探讨与实现如何于多用户的环境下共享相同的系

一文读懂原码、反码与补码

一、二进制二进制和十进制一样,也是一种进位计数制,但是它的基数是2。二进制表达式中0和1的位置不同,它所代表的数值也不同。例如,二进制数00001010表示十进制数10。一个二进制数具有两个基本特点:

一文读懂云原生 go-zero 微服务框架

课程推荐:GO开发工程师--学习猿地精品课程 go-zero介绍从今年8月7日github开源以来,已经获得了2700+star的go-zero是一个集成了各种工程实践的web和rpc框架。通过弹性设

python __slots__ 魔法

在Python中,每个类都有实例属性。默认情况下Python用一个字典来保存一个对象的实例属性。这非常有用,因为它允许我们在运行时去设置任意的新属性。 然而,对于有着已知属性的小类来说,它可能是个瓶颈

一文带你掌握常见的Pandas性能优化方法,让你的pandas飞起来!

微信公众号:「Python读财」如有问题或建议,请公众号留言Pandas是Python中用于数据处理与分析的屠龙刀,想必大家也都不陌生,但Pandas在使用上有一些技巧和需要注意的地方,尤其是对于较大

【python测试开发栈】帮你总结python time模块高频使用方法

在平时写python脚本时,时间是我们经常用到的数据,比如:时间戳、前端展示的对应格式的时间等,在python中主要有三个和时间处理相关的模块:time、datetime、calendar,这篇文章主

Python 教程-了解Python

什么是Python Python能干什么? 有什么特点? 什么是Python 官方介绍: Python是一个易于学习、功能强大的编程语言。它拥有高效高级的数据结构和一种简单有效的面向对象编程的

Python 教程-Python 安装

在Windows上安装 访问https://www.python.org/downloads/并下载最新版本。在撰写时当前最新是3.8。在安装的时候和其他软件一样,无脑式下一步。需要注意的是如果在W

Python入门教程_2. 使用 Python 解释器

2.1.调用解释器 Python解释器通常安装在目标机器上的/usr/local/bin/python3.7目录下;把/usr/local/bin目录放进你的Unixshell的搜索路径里,确保它可以

Python入门教程_3. Python 简介

在下面的例子中,输入和输出分别由大于号和句号提示符(>>>和...)标注:如果想重现这些例子,就要在解释器的提示符后,输入(提示符后面的)那些不包含提示符的代码行。需要注意的是在练习中遇到的从属提示符

Python入门教程_4. 深入 Python 流程控制

除了刚刚介绍的while语句,Python还有一些在其他语言中常见的控制流语句,并做了一些改动。 4.1.if语句 也许最著名的语句是if语句了。 例如: >>>x=int(input("Please

【python测试开发栈】帮你总结python random模块高频使用方法

随机数据在平时写python脚本时会经常被用到,比如随机生成0和1来控制逻辑、或者从列表中随机选择一个元素(其实抽奖程序也类似,就是从公司所有人中随机选择中奖用户)等等。这篇文章,就帮大家整理在pyt

流畅的Python读书笔记 --- 第一章 Python数据模型

近期开始读“流畅的Python”这本书,想把自己的读书笔记分享给大家,希望能帮到也对这本书感兴趣但是没时间看的各位。(文章中大部分的话和图片摘录总结自“流畅的Python”一书,以及python官方网

【Python 1-5】Python教程之——字符串

课程推荐:Python开发工程师--学习猿地--送9个上线商业项目 字符串字符串就是一系列字符。在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号,如下所示:"Thisi

漫谈:Java和Python现在都挺火,我应该怎么选?Java和Python优缺点比较。

课程推荐:Java开发工程师--学习猿地精品课程课程推荐:Python开发工程师--学习猿地精品课程 声明:这是一篇容易引起撕逼的文章,为了祖国和谐,人民安康,请各位看官尽量理性讨论。同时,这篇文章是

【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

Java并发基础常见面试题总结 1.什么是线程和进程? 1.1.何为进程? 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。

python自动化测试学习 - Pytest插件之selenium

推荐课程《Python开发工程师--学习猿地精品在线课》今天主要演示Pytest框架的selenium插件。webdriver是主流的UI自动化测试框架,在Pytest的测试框架中也提供了对webdr

node_modules是什么文件夹?

node_modules是安装node后用来存放用包管理工具下载安装的包的文件夹。比如webpack、gulp、grunt这些工具。npminstall执行完毕后,我们可以在node_modules中

一篇文章读懂“GAN”——生成式对抗网络

机器学习是一个不断发展的领域,因此对于很多人来说,时刻跟踪这一领域的最新进展是很难的。GAN(生成式对抗网络)是最近引起广泛关注的新兴领域之一,为了让大家能够更好地跟上技术发展的脚步,我们安排了一个简

一图读懂POLARDB BOX的云原生力量

9月26日,2019杭州云栖大会上,阿里云宣布正式推出高性能数据库一体机——POLARDBBOX,用户部署在自有数据中心即可享受云数据库的便捷体验,同时还为Oracle等传统数据库用户提供一键迁移功能

一张图读懂《2020全球网络趋势报告》

日前,思科发布了《2020全球网络趋势报告》,从网络技术、运营、人才三大维度,了解网络如何与时俱进,满足关键业务需求。那么这份94页的报告,究竟有哪些亮点?戳下图,带你看明白!

Python中的openpyxl如何对excel修改文件

推荐课程:Python开发工程师--学习猿地--送9个上线商业项目 Python安装openpyxl 首先我们应该配置pip详细配置教程地址:https://blog.csdn.net/hanhanw

Google 21 岁生日,一文回顾 Google 发展史

9月27日,谷歌在Google搜索引擎首页庆祝自己21岁生日。 在涂鸦存档上,谷歌发布了一封庆祝信: 21年前,两位斯坦福大学博士生谢尔盖·布林和拉里·佩奇发表了一篇有关启动“大型搜索引擎”原