运行Python代码通常有以下几种方式:
1、Python Shell 即原生的 Python 交互解释器,可以让你以交互模式使用 Python 解释器,但退出后,再次进入 Python Shell时,之前定义的函数和变量就丢失了。
2、编写较长程序时,可用文本编辑器代替交互解释器,编写代码后存为.py文件,再执行.py文件中的代码内容,即:编写和运行Python脚本 。但随着编写的程序越来越长,为了方便维护,需要把脚本拆分成多个文件。
3、Python 可把各种定义、方法等存入一个单独的文件中,在脚本或解释器的交互式实例中使用,这个文件就是模块。模块是包含 Python 定义和语句的文件,其文件名是模块名加后缀名 .py 。在模块内部,通过全局变量 name 可以获取模块名(即字符串)。
模块可有逻辑地组织 Python 代码,把完成某些类似功能相关的代码分配到一个模块里能让代码更具封装性,在模块内可定义函数、类和变量,也可包含可执行的代码。此外,模块中的定义可导入到其他模块或主模块。
模块包含可执行语句及函数定义。这些语句用于初始化模块,且仅在 import 语句第一次遇到模块名时执行。
模块有自己的私有符号表,用作模块中所有函数的全局符号表。因此,在模块内使用全局变量时,不用担心与用户定义的全局变量发生冲突。在模块内,还可以把其他模块导入本模块。
访问模块定义的函数和变量可采用如下格式:
模块名.函数
模块名.变量
导入模块的方式通常是以下几种:
1、导入的模块名存在导入模块的全局符号表里。
Import 模块名
2、import 语句有一个变体,可以直接把模块里的名称导入到另一个模块的符号表。
from 模块名 import 函数1, 函数2…(或变量列表,以逗号分隔)
上面格式不会把模块名导入到局部符号表里
3、使用* 可以导入模块内定义的所有名称:
from 模块名 import *
上面这种方式会导入所有不以下划线(_)开头的名称,但这种方式会向解释器导入了一批未知的名称,可能会覆盖已经定义的名称。
4、模块名后使用 as 时,直接把 as 后的名称与导入模块绑定。
import 模块名 as 模块别名
from 模块名 import 函数列表(或变量列表,以逗号分隔)as 别名
按编码惯例,所有 import 语句都放在模块(或脚本)开头,但不是硬性规定,这意味着可以按需导入模块,即:将导入模块语句放在条件语句中,当条件满足时再导入模块。
模块文件可作为脚本单独运行,就也就是说直接执行模块里的代码。可使用以下方式单独运行 Python 模块:
python 模块文件名(以.py结尾模块) <参数列表>
但有时候执行模块文件只是为了测试或其它目的,不一定执行模块内的代码。因此,可利用变量__name__来执行特定代码,单独执行模块代码时,name 将赋值为 "main”,name 是内置变量,用于表示当前模块的名字。可将把下列代码添加到模块末尾:
if name == “main”:
#当程序被单独执行时需要执行的语句
…
…
对if name == ‘main’ 可这么理解: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行。
这样模块文件即当脚本使用,也可以用作导入的模块。
下面定义一个模块testModule262,模块包括2个方法,完成数的累加,其中一个方法(sumN)返回累加结果,另一个方法(printSum)向屏幕打印累加过程。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#testModule262.py
def sumN(n):
sum=0
for i in range(n):
sum+=i
return sum
def printSum(n):
sum=0
for i in range(1,n):
sum+=i
print(i," sum:",sum)
def main():
print(sumN(6))
if __name__ == "__main__":
main()
exit()
printSum(6)
可直接执行上述模块。
>python testModule262.py
输出结果如下:
15
因为模块代码是单独执行的,name__值为__main,条件语句中的条件满足,只会执行下面代码,第1行调用main函数,输出sumN(6)的结果,第2行退出程序,程序的最后2行没有机会执行。
main()
exit()
那最后2行在什么情况下会执行呢?最后2行会在模块被导入时执行。最后2行代码是:
print(name)
printSum(6)
最后2行先输出__name_变量值,再打印0-6累加过程。
编写程序2-6-2.py,导入testModule262模块。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-6-2.py
import testModule262
print(testModule262.sumN(10))
执行2-6-2.py,程序将输出__name_变量值(导入模块名),然后 打印0-6 的累加过程(printSum(6)),最后,输出0-9的累加结果执行程序。结果如下:
testModule262
1 sum: 1
2 sum: 3
3 sum: 6
4 sum: 10
5 sum: 15
45
包是一种用“点式模块名”构造 Python 模块命名空间的方法。例如,模块名 A.B 表示包 A 中名为 B 的子模块。正如模块可以区分不同模块之间的全局变量名称一样,点式模块名可以区分 NumPy 或 Pillow 等不同多模块包之间的模块名称。
包的目录组织规则如下:
(1)每个目录下需要建立一个__iniit__.py的文件,空文件也可以,这样才可以引入该目录下的模块。
(2)init.py 文件定义了包的属性和方法。其实它可以什么也不定义;可以只是一个空文件,但是必须存在。
(3)目录名就是包名。
(4)__all__在from … import *的情况下使用。
接下来,以一个实例深入解析模块及包。
1、建立以下目录组织:
m1
--__init__.py
--test1.py
--m2
--__init__py
--test2.py
在以上文件目录中。
(1)2个__init__.py都为空文件。
(2)test1.py内容如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def test1():
print("test1.py")
(3)test2.py内容如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def test2():
print("test2.py")
>>> import m1.test1
>>> m1.test1.test1()
m1.test1
>>> from m1.test1 import test1
>>> test1()
m1.test1
>>> from m1 import test1
>>> test1.test1()
m1.test1
>>> print(m1.__name__)
m1
>>> print(m1.test1.__name__)
m1.test1
>>> from m1.m2 import test2
>>> test2.test2()
m1.m2.test2
>>> import m1.m2
>>> m1.m2.test2.test2()
m1.m2.test2
>>> import m1.m2.test2
>>> m1.m2.test2.test2()
m1.m2.test2
>>> from m1.m2.test2 import test2
>>> test2()
m1.m2.test2
>>>
>>> import m1.test1 as t1
>>> t1.test1()
m1.test1
包下的__init__.py文件内容为空,导入包是无法使用的
>>> from m1 import *
>>> m1.test1.test1()
Traceback (most recent call last):
File "" , line 1, in <module>
AttributeError: module 'm1' has no attribute 'test1'
>>>
下面来为__init__.py写内容
(base) [myhaspl@localhost m1]$ pwd
/home/myhaspl/learn/learnpy/learn2/m1
(base) [myhaspl@localhost m1]$ cat __init__.py
import m1.test1
(base) [myhaspl@localhost m1]$
>>> import m1
>>> m1.test1.test1()
m1.test1
(base) [myhaspl@localhost learn2]$ cat ./m1/m2/__init__.py
import m1.m2.test2
(base) [myhaspl@localhost learn2]$
>>> import m1.m2
>>> m1.m2.test2
<module 'm1.m2.test2' from '/home/myhaspl/learn/learnpy/learn2/m1/m2/test2.py'>
>>> m1.m2.test2.test2()
m1.m2.test2
在m1目录下再加入test11.py
然后,修改m1/__init__.py,加入__all__以及test11.py
(base) [myhaspl@localhost learn2]$ cat m1/__init__.py
import m1.test1
import m1.test11
__all__ = ["test1","test11"]
>>> from m1 import *
>>> test1
<module 'm1.test1' from '/home/myhaspl/learn/learnpy/learn2/m1/test1.py'>
>>> test11
<module 'm1.test11' from '/home/myhaspl/learn/learnpy/learn2/m1/test11.py'>
>>>
接着,修改m2目录的__init__.py文件。
(base) [myhaspl@localhost learn2]$ cat m1/m2/__init__.py
import m1.m2.test2
__all__=["test2"]
(base) [myhaspl@localhost learn2]$
>>> from m1.m2 import *
>>> test2
<module 'm1.m2.test2' from '/home/myhaspl/learn/learnpy/learn2/m1/m2/test2.py'>
使用以下格式导入同级目录(包)下的模块
from .模块名(注意此处不是包名) import 模块下定义的类名或函数名等等
(base) [myhaspl@localhost learn2]$ cat m1/test11.py
from .test1 import test1
def test11():
test1()
print("m1.test11")
(base) [myhaspl@localhost learn2]$
>>> import m1
>>> m1.test11.test11()
m1.test1
m1.test11
>>>
加入对__name__的支持,检测直接运行还是调用
(base) [myhaspl@localhost learn2]$ python m1/test11.py
m1.test1
m1.test11
>>> import m1
>>> m1.test1.test1()
m1.test1
>>> m1.test11.test11()
m1.test11
>>> quit()
(base) [myhaspl@localhost learn2]$ cat m1/test1.py
def test1():
print("m1.test1")
(base) [myhaspl@localhost learn2]$ cat m1/test11.py
def test11():
print("m1.test11")
def main():
from test1 import test1
test1()
test11()
if __name__=="__main__":
main()
(base) [myhaspl@localhost learn2]$ python m1/test11.py
m1.test1
m1.test11
(base) [myhaspl@localhost learn2]$