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

程序入口

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

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

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

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

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

我们在这个文件里边定义了一些常量,然后又写了一个 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.14
round 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",输出结果:

a
a.b
a.b.c

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

import tornado
import 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.pypython -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.py
import sys
print "__init__"
print sys.path
  • main.py
import 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 是有无限可能的,你可以写出很多简洁优雅的代码。

参考资料

  • http://www.tuicool.com/articles/jMzqYzF
  • http://stackoverflow.com/questions/4042905/what-is-main-py

原文链接:https://blog.csdn.net/jiuzhibuguniao/article/details/80456675

__name__的用法相关推荐

  1. python——实例详细弄懂if __name__ == ‘__main__‘用法

    前言:在python慢慢学习路中,经常会遇到if __name__ == "__main__",而且会发现不写这句话,代码依旧可以执行.心里就有一百个疑问,通过大神指导,小编终于理 ...

  2. Python版归并排序算法(附Python程序__name__属性用法演示视频)

    import random def mergeSort(seq, reverse=False): #把原列表分成两部分 mid = len(seq) // 2 left, right = seq[:m ...

  3. sys.modules[__name__]的一个实例

    关于sys.modules[__name__]的用法,百度上阅读量比较多得一个帖子是:https://www.cnblogs.com/robinunix/p/8523601.html 对于里面提到的基 ...

  4. Python基础16-模块与包基础01

    目录 初识模块和包 Python常用的内置模块 关键字import和from import.from查找的路径 如何调用 __name__与模块执行 __name__的用法(单元测试) 初识模块和包 ...

  5. Python版插入排序算法

    问题描述:在插入排序算法中,把所有元素分为前面的已排序序列和后面的未排序序列两部分,每次处理未排序序列中的第一个元素,将其插入到前面已排序序列中的合适位置,从而不停地扩大已排序序列并缩小未排序序列,直 ...

  6. 使用Python+pillow绘制矩阵盖尔圆

    盖尔圆是矩阵特征值估计时常用的方法之一,其定义为: 与盖尔圆有关的两个定理为: 定理1:矩阵A的所有特征值均落在它的所有盖尔圆的并集之中. 定理2:将矩阵A的全体盖尔圆的并集按连通部分分成若干个子集, ...

  7. Python实现大自然数分解为最多4个平方数之和(1)

    问题描述:任意大自然数,总是能分解为最多4个平方数的和,所谓平方数是指它是一个自然数的平方.例如:72884 = 4^2 + 138^2 + 232^2,33788 = 1^2 + 3^2 + 17^ ...

  8. 使用Python模拟蒙蒂霍尔悖论游戏

    假设你正参加一个有奖游戏节目,并且有3道门可选:其中一个后面是汽车,另外两个后面是山羊.你选择一个门,比如说1号门,主持人当然知道每个门后面是什么并且打开了另一个门,比如说3号门,后面是一只山羊.然后 ...

  9. 一个傻傻的尼姆游戏及其Python实现

    尼姆游戏是个著名的游戏,有很多变种玩法.两个玩家轮流从一堆物品中拿走一部分.在每一步中,玩家可以自由选择拿走多少物品,但是必须至少拿走一个并且最多只能拿走一半物品,然后轮到下一个玩家.拿走最后一个物品 ...

最新文章

  1. TensorFlow 官方文档中文版发布啦(持续维护)
  2. Zabbix的聚合图形配置
  3. Link-Cut Tree指针模板
  4. 纯手写的css3正方体旋转效果
  5. 「浏览器插件」网址小尾巴终结者
  6. 【Python 标准库学习】数据科学计算库 — math
  7. 【HDU5091】Beam Cannon,扫描线+线段树
  8. python系统学习:第二周之购物车功能
  9. K_Nearest_Neighbot(knn)方法及其Pyhon 实现
  10. 什么是持续集成(CI)/持续部署(CD)?
  11. 【网络流24题】星际转移问题(最大流)(网络判定)
  12. 第七章思维导图前半段
  13. 高铁:繁忙时限制上车补票
  14. linux mysql 开发_Linux64下mysql安装和开发
  15. java jsonobject_Java调用groovy及如何使用springBean
  16. 使用POI导出Excel时,关于设置带有多行表头表格自动宽度的问题解决办法
  17. wasm(jsC++)0-开发环境搭建
  18. django 改端口_django更改默认的runserver端口
  19. APP开发要么快要么死!
  20. c语言scanf()的返回值

热门文章

  1. 【opencv人脸识别1】从图片中检测人脸
  2. socket编程接口
  3. android 集成腾讯IMSDK4.2.9 TUIKIT即时通信之更改头像
  4. Surely Vue-去除水印
  5. 【特征检测】BRISK特征提取算法
  6. Web 函数自定义镜像实战:构建图象处理函数
  7. 实现移动端H5页面调用摄像头
  8. 20154312 曾林 Exp8 web基础
  9. jacob java excel_使用 Jacob 操作Excel、Word文件
  10. Balsamiq Mockups简单介绍(UI草图绘制工具)