python中if __name__ == '__main__'的使用

在大多数编排得好一点的脚本或者程序里面都有这段if name == ‘main’:
,虽然一直知道他的作用,但是一直比较模糊,收集资料详细理解之后与大家分享。

一个python的文件有两种使用的方法,第一是直接作为脚本执行,第二是import到其他的python脚本中被调用(模块重用)执行。因此if name == ‘main’: 的作用就是控制这两种情况执行代码的过程,在if name == ‘main’: 下的代码只有在第一种情况下(即文件作为脚本直接执行)才会被执行,而import到其他脚本中是不会被执行的。
可借鉴参考: https://blog.csdn.net/xiaoxik/article/details/78749361

首先定义了一个test.py的文件,然后再定义一个函数,并在函数定义后直接运行:

test.py

def HaveFun():
    if __name__ == '__main__':
        print('I am in my domain,my name is %s' % __name__)
    else:
        print('Someone else calls me!,my name is %s' % __name__)


HaveFun()

运行test.py结果:

I am in my domain,my name is __main__

然后继续创建一个main.py的文件,程序如下:

main.py

import test

test.HaveFun()

执行main.py文件,结果如下:

Someone else calls me!,my name is test
Someone else calls me!,my name is test

这里打印了两次,第一次实在main.py在进行import test的时候,进行的打印,第二次才是test.HaveFun()中执行的打印,可以发现,这里的
__name__名称已经发成了变化,从之前的main变成了模块名称test。

总结:
1、__name__这个系统变量显示了当前模块执行过程中的名称,如果当前程序运行在这个模块中,__name__ 的名称就是__main__如果不是,则为这个模块的名称。
2、__main__一般作为函数的入口,类似于C语言,尤其在大型工程中,常常有if __name__ == "__main__":来表明整个工程开始运行的入口。




再如:

背景
初学者在学习Python的过程中,一定都遇到过if __name__ == '__main__'这样的语句。那么,这样的一个语句有什么作用呢?在什么时候需要使用这个判断语句呢?

举个例子
执行:

def main():
    print "hello world!"
    print __name__

if __name__ == '__main__':
 main()

print __name__

文件名为:test.py
执行结果为:
在这里插入图片描述
可以看到,直接执行该模块,__name__变量为__main__
执行:

import test

文件名为:test1.py
执行结果为:
在这里插入图片描述
可以看到,将test作为模块导入另一个文件中,得到的结果为test。
这是因为在导入test模块后,也会执行该模块。当__name____main__时才会执行main()。
然而test作为模块导入另一个文件时,__name__为模块名:test。因此最后只打印了一个test。

语句的作用

我们应该都知道类似__xxx__这种形式的变量是python的内置变量,在声明用户变量时不可以与内置变量重复。而这个__name__内置变量代表的是模块名(模块也就是python文件)。该模块名在直接运行模块时为__main__,在作为模块导入时为模块本身名称。
所以,这个语句的作用就是:当该模块直接运行时执行if__name__=='__main__'中的语句。当该模块作为模块导入到别的文件中时,因为__name__不为__main__,于是这个判断中的语句不能被执行。




又如:

https://blog.csdn.net/zhuzuwei/article/details/78247841

1、导入模块时,如果导入的新模块不在当前模块所在同一路径下,那么直接import会出错。解决办法有:

(1)如果当前模块和要导入的模块属于不同的包,但是包的上级路径是一样的,那么可以直接import 包名.模块名,如import myPackeg.myModule,要求脚本文件与此包在同一级别。。

(2)可以先将要导入的模块加入sys.path中,再import. 如下示例:导入F:\DeepLearning目录下的test1模块(也就通过增加搜索路径的方式,哪都能找到它。。)

 >>> import test1
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import test1
ModuleNotFoundError: No module named 'test1'
>>> import sys
>>> sys.path
['', 'D:\\Program Files\\Python\\Lib\\idlelib', 'D:\\Program Files\\Python\\python36.zip', 'D:\\Program Files\\Python\\DLLs', 'D:\\Program Files\\Python\\lib', 'D:\\Program Files\\Python', 'D:\\Program Files\\Python\\lib\\site-packages']
>>> sys.path.append('F:\\DeepLearning')
>>> sys.path
['', 'D:\\Program Files\\Python\\Lib\\idlelib', 'D:\\Program Files\\Python\\python36.zip', 'D:\\Program Files\\Python\\DLLs', 'D:\\Program Files\\Python\\lib', 'D:\\Program Files\\Python', 'D:\\Program Files\\Python\\lib\\site-packages', 'F:\\DeepLearning']
>>> import test1
>>>

2. if name == 'main’语句的使用

先看tc模块和calc模块的代码
calc模块代码:

import tc
print("32摄氏度 = %.2f华氏度"%tc.c2f(32))
print("99华氏度 = %.2f摄氏度"%tc.f2c(99))

tc模块代码:

def c2f(cel):
    fah = cel * 1.8 + 32
    return fah
 
def f2c(fah):
    cel = (fah - 32) / 1.8
    return cel
 
def test():
    print("测试,0摄氏度 = %.2f华氏度"%c2f(0))
    print("测试,0华氏度 = %.2f摄氏度"%f2c(0))
 
test()

运行calc模块后:

>>> runfile('F:/DeepLearning/calc.py', wdir='F:/DeepLearning')
Reloaded modules: tc
测试,0摄氏度 = 32.00华氏度
测试,0华氏度 = -17.78摄氏度
32摄氏度 = 89.60华氏度
99华氏度 = 37.22摄氏度

将测试语句的函数test()也执行了,如果要避免直接执行test()函数,可以将tc模块中最后一句test()语句改为:

if __name__ == '__main__':
    test()

再执行就是

>>>     runfile('F:/DeepLearning/calc.py', wdir='F:/DeepLearning')
Reloaded modules: tc
32摄氏度 = 89.60华氏度
99华氏度 = 37.22摄氏度

查看__name__属性:

>>> __name__
'__main__'
>>> tc.__name__
'tc'

这是因为__name__就是标识模块的名字的一个系统变量。这里分两种情况:假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是__main__,通过if判断这样就可以执行“__main__:”后面的主函数内容;假如此模块是被import的,则此模块名字为文件名字(不加后面的.py),通过if判断这样就会跳过“__mian__:”后面的内容。上例中,tc.__name__不是'main',所以tc模块中的“__mian__:”后面的语句就没有被执行




这里还有一篇博客写的很好,但是其中有些知识比较冷门,用的不怎么多。
http://blog.konghy.cn/2017/04/24/python-entry-program/

1. 摘要

通俗的理解__name__ == '__main__'假如你叫小明.py,在朋友眼中,你是小明( __name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')。

if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。

2. 程序入口

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

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

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

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

PI = 3.14

def 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 PI

def 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.14

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

if __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

猜你喜欢

转载自blog.csdn.net/edward_zcl/article/details/88797961