在上一篇《老男人开始学python之Flask中的“Hello World”》中,虽然只按照教程写了几行短短的代码,但是对于初学者的我来说就产生了一些疑问,有一些不明白的地方?
- 为什么文件名是“
__init__.py
”? - “
__name__
”是什么? - from ... import ... 是什么意思?
- form ... import ... 和 import ...的区别是什么?
带着问题去看了Python基础教程模块一节记录总结一下。
参考教程:
廖雪峰:模块、使用模块、安装第三方模块
链接:http://www.liaoxuefeng.com/
一、什么是模块、包、库?
| Module(模块)| Package(包)| Library(库)|
| --------------------- | :------------------ | --------------- -: |
| 一个.py
文件就称之为一个模块(Module)| 只要包含__init__.py
文件的文件夹就叫做包| 参考其他编程语言的说法。就是指Python中完成一定功能的代码集合,供用户使用的代码组合。在python中是包和模块的形式 | | abc.py模块名就是abc;|1.
init.py文件必须存在,否则就是一个文件夹;2.
init.py文件可以为空,也可以有python代码;3. 可以有多级层次结构包含多个模块或子包组成;4.
init.py`文件本身就是一个模块,模块名就是包含它的文件夹的名称; |例如常说的第三方库,是否可以简单理解为包含多个Package(包)完成某功能的一个代码集合 |
1.Package 包中都可以包含什么?
F:\pythontest\test2.py # test2模块
F:\pythontest\test3 # test3文件夹中包含__init__.py文件,因此是一个包;
│ a.py # test3.a模块;
│ b.py # test3.b模块;
│ __init__.py # 也是一个模块,名称是:test3
│
├─b # 包含2个模块的一个【文件夹】,但是名称和test3.b名称同名了,该【文件夹】下的模块能正常使用吗?如果这里是个同名的子包呢?
│ a.py
│ b.py
│
├─c # 一个空【文件夹】
├─d # 因为包含__init__.py文件,因此是一个子包
│ a.py # 模块名:test3.d.a
│ b.py # 模块名:test3.d.a
│ __init__.py # 模块名:test3.d
│
└─e # 包含2个模块的一个【文件夹】,该文件夹下的2个模块能用吗?
a.py # 暂认为模块名为:test3.e.a
b.py # 暂认为模块名为:test3.e.b
如上所示,一个包中可以包含:模块(a、b)、包含模块的文件夹(b、e)、空文件夹(c)、子包(d)。
【说明】到了这里解决了第1个问题,为什么文件名是“__init__.py
”,因为它是一个Package(包);
下边做一些测试:
#F:\pythontest\test3\a.py代码如下:
def a():
return "my name is 'a'"
#F:\pythontest\test3\b.py代码如下:
def b():
return "my name is 'b'"
#F:\pythontest\test3\b\a.py代码如下:
def a():
return "我是B文件夹下的 'a'"
#F:\pythontest\test3\b\b.py代码如下:
def b():
return "我是B文件夹下的 'b'"
#F:\pythontest\test3\d\a.py代码如下:
def a():
return "我是D子包中的 'a'"
#F:\pythontest\test3\d\b.py代码如下:
def b():
return "我是D子包中的 'b'"
__init__.py
文件全部为空,F:\pythontest\test2.py
文件中代码分别为如下几种情况的执行结果:
-----------------------------------------------------------------------------------
import test3
x = test3.a.a()
print (x)
#执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
Traceback (most recent call last):
File "test2.py", line 2, in
x = test3.a.a()
AttributeError: 'module' object has no attribute 'a'
【总结】:因为导入的模块名为test3,也就是test3文件夹下的`__init__.py `文件,而该文件为空,所以找不到test3.a模块中的a函数;
-----------------------------------------------------------------------------------
使用import test3.a 导入test3.a模块,即test3文件夹下的a.py文件,就可以正常执行:
import test3.a
x = test3.a.a()
print (x)
#执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
my name is 'a'
-----------------------------------------------------------------------------------
#代码如下:
import test3.b
x = test3.b.b()
print (x)
#执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
my name is 'b'
#代码更改如下:测试导入b文件夹中的b模块
import test3.b.b
x = test3.b.b.b()
print (x)
#执行结果:没有模块test3.b.b,test3.b不是一个包;
F:\pythontest>flask\Scripts\python.exe test2.py
Traceback (most recent call last):
File "", line 2218, in _find_and_load_unlocked
AttributeError: 'module' object has no attribute '__path__'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test2.py", line 1, in
import test3.b.b
ImportError: No module named 'test3.b.b'; 'test3.b' is not a package
-----------------------------------------------------------------------------------
如果给b文件夹下放一个空__init__.py文件,这时候b文件夹就成了test3的一个子包则:
import test3.b
x = test3.b.b()
print (x)
#执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
Traceback (most recent call last):
File "test2.py", line 2, in
x = test3.b.b()
AttributeError: 'module' object has no attribute 'b'
【总结】因为导入test3.b模块的时候实际上b子包把test3.b模块覆盖了,实际上导入的是b文件夹中的__init__.py文件,而该文件为空,因此找不到b函数;
#更改代码如下:导入test3.b模块,即test3\b\__init__.py
import test3.b
x = test3.b.a.a()
print (x)
#同时修改test3\b\__init__.py文件代码如下:
import test3.b.a
#执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
我是B文件夹下的 'a'
这个时候就是test3\b\__init__.py文件中导入了test3.b.a模块,然后在test2.py文件中导入了test3.b模块即test3\b\__init__.py文件,换句话说就是在test3\b\__init__.py文件中引入了test3\b\a.py文件,然后在test2.py文件中又引入了test3\b\__init__.py文件,因此a.py中的a函数能被正常执行。
-----------------------------------------------------------------------------------
#最后来看看e文件夹中的模块文件能否被正常导入并使用模块中的函数?
代码如下:
import test3.e.a
x = test3.e.a.a()
print (x)
#执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
我是E文件夹下的 'a'模块
从执行结果来看,是可以正常运行的。
更改一下代码:
import test3.e
x = test3.e.a.a()
print (x)
执行结果:
F:\pythontest>flask\Scripts\python.exe test2.py
Traceback (most recent call last):
File "test2.py", line 2, in
x = test3.e.a.a()
AttributeError: 'module' object has no attribute 'a'
从以上两例测试,可以看到虽然e只是个文件夹不是子包,但是该文件夹下的模块文件依然可以被导入。
上边的两个问题:
- 含2个模块的一个【文件夹】,但是名称和test3.b名称同名了,该【文件夹】下的模块能正常使用吗?如果这里是个同名的子包呢?
如果在test3包中,含有一个b.py和一个b文件夹,则b.py文件(模块)可以被导入,而b文件夹中的.py文件不能被导入;
如果b文件夹是一个子包,则子包覆盖b.py;
【注意】不要重名,以免混淆! - 文件夹e,不是子包,该文件下包含2个.py文件(模块),该文件夹下的2个模块能用吗?
可以被导入使用。这是为什么呢?
二、如何使用Module(模块)?
import 命令为导入Module(模块)命令,而Module指的就是一个.py文件,其实就可以认为是在一个.py文件中引入另外一个.py文件。
1. 使用导入Module(模块)命令import
有几种格式:
命令 | 解释 |
---|---|
import module | 导入单个模块 |
import module as name | 导入单个模块并重命名 |
import moudule1, moudule2,module3,... | 一次导入多个模块 |
import moudule1 as name1,module2 as name2,... | 一次导入多个模块并重命名 |
一般在文件首部导入所有模块,推荐顺序如下:
python标准库
第三方模块
应用程序自定义模块
2. 使用from...import...语句导入模块的属性(变量、函数、对象)
命令 | 解释 |
---|---|
from module import name1,name2,name3 | 单行导入 |
from module import name1,name2,\ name3 | 多行导入 |
from module import * | 导入全部属性,一般不推荐使用,适合模块中变量名很长和很多的情况。容易覆盖当前命名空间中现有的名字 |
当试图加载一个模块的时候,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错。
默认情况下,Python解释器会搜索当前文件夹、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中。
有两种方法修改搜索路径:
一是直接修改sys.path,添加要搜索的文件夹:sys.path.append('路径')
第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
模块被导入时,加载的时候模块顶层代码会被执行,一个模块无论被导入多少次,只加载一次,可以防止多次导入时代码被多次执行。
内建函数reload可以重新导入一个已经存在的模块。
三、 “__name__
”是什么?
简单的说:
1.如果模块(就是一个.py)文件是直接执行的,则__name__
值就等于__main__
;
2.如果模块是被导入的时候,__name__
的值就是模块名;
#test_name2.py 代码为:
def test_name2(): # 定义一个函数test_name2
b = __name__ # 将__name__赋值给变量b
return b # 函数返回变量b的值
if __name__ == "__main__": # 如果__name__ 等于字符串__main__ 就可以认为是直接执行的test_name2.py文件,则打印test_name2()函数的返回值;
print (test_name2())
#test_name1.py 代码为:
import test_name2 # 导入模块 test_name2
print (test_name2.test_name2()) # 打印test_name2模块中的test_name2函数值;
直接执行test_name2的结果:结果为__main__
F:\pythontest>flask\Scripts\python.exe test_name2.py
__main__
直接执行test_name1的结果:结果为模块名
F:\pythontest>flask\Scripts\python.exe test_name1.py
test_name2
可做调试代码用;
参考:
python:浅析python 中name = 'main' 的作用
python中name的使用