程序入口
对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# 等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C 和 C++ 都需要有一个 main 函数来作为程序的入口,也就是程序的运行会从 main 函数开始。同样,Java 和 C# 必须要有一个包含 Main 方法的主类来作为程序入口。
而 Python 则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。
一个 Python 源码文件除了可以被直接运行外,还可以作为模块(也就是库)被导入。不管是导入还是直接运行,最顶层的代码都会被运行(Python 用缩进来区分代码层次)。而实际上在导入的时候,有一部分代码我们是不希望被运行的。
举一个例子来说明一下,假设我们有一个const.py
文件,内容如下:
PI = 3.14
def main():
print ("PI:", PI)
mian()
我们在这个文件里边定义了一些常量,然后又写了一个 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()
#输出:
#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__'
我们简单的理解就是: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行。
Python使用缩进对齐组织代码的执行,所有没有缩进的代码,都会在载入时自动执行。每个文件(模块)都可以任意写一些没有缩进的代码,并在载入时自动执行。为了区分 主执行代码和被调用文件,Python引入了变量:name。
1)当文件是被调用时,__name__
的值为模块名;
2)当文件被执行时,__name__
的值为 ‘__main__’
。
基于此特性,为测试驱动开发提供了很好的支持,我们可以在每个模块中写上测试代码,这些测试代码仅当模块被Python直接执行时才会运行,代码和测试完美的结合在一起。
Python中的__name__
举例
__name__
: 是否为主文件
#hello.py
def sayHello():
str='hello'
print(str)
if __name__=='__main__':
print(('this is main of module "hello.py"'))
sayHello()
python作为一种脚本语言,我们用python写的各个module都可以包含以上那么一个类似c中的main函数,只不过python中的这种__main__
与c中有一些区别,主要体现在:
1、当单独执行该module时,比如单独执行上面的hello.py程序: python hello.py
,则输出
this is main of module "hello.py"
hello
可以理解为f __name__=="__main__":
" 这一句与c中的main()函数所表述的是一致的,即作为入口;
2、当该module被其它module 引入使用时,其中的"if __name__=="__main__":
"所表示的Block不会被执行,这是因为此时module被其它module引用时,其__name__
的值将发生变化,__name__
的值将会是module的名字。比如在python shell中import hello后,查看hello.__name__
:
>>> import hello
>>> hello.__name__
'hello'
>>>
3、在python中,当一个module作为整体被执行时,moduel.__name__
的值是"__main__"
;
当一个module被其它module引用时,module.__name__
将是module自己的名字;
当然一个module被其它module引用时,其本身并不需要一个可执行的入口main了。
#执行index.py
demo: file.demo
demo: demo
index: __main__
#执行index.py
demo: file.demo
index: __main__
注意:
- 单独执行任何一个文件时,输出都是 :
__main__
- 通过文件被导入执行时,输出是: 模块名.文件名
- 通过文件导入执行时,导入语句根据两个文件是否在一个文件夹(模块)下,有所不同
- from 模块名 import 文件名 或 from 文件名 import 方法名
__file__
、__doc__
的用法
__file__
:当前文件路径
__doc__
: 当前文件描述
#index.py
'''
Create on XXXX
@author:HHHH
'''
print(__file__)
print(__doc__)
#打印
F:/CodeFile/Python1/file2/index.py
Create on XXXX
@author:HHHH
参考:https://blog.csdn.net/mingyuli/article/details/80956951
http://blog.konghy.cn/2017/04/24/python-entry-program/