老男人开始学python之什么是模块、包、库?

在上一篇《老男人开始学python之Flask中的“Hello World”》中,虽然只按照教程写了几行短短的代码,但是对于初学者的我来说就产生了一些疑问,有一些不明白的地方?

  1. 为什么文件名是“__init__.py”?
  2. __name__”是什么?
  3. from ... import ... 是什么意思?
  4. 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只是个文件夹不是子包,但是该文件夹下的模块文件依然可以被导入。

上边的两个问题:

  1. 含2个模块的一个【文件夹】,但是名称和test3.b名称同名了,该【文件夹】下的模块能正常使用吗?如果这里是个同名的子包呢?

    如果在test3包中,含有一个b.py和一个b文件夹,则b.py文件(模块)可以被导入,而b文件夹中的.py文件不能被导入;
    如果b文件夹是一个子包,则子包覆盖b.py;
    【注意】不要重名,以免混淆!

  2. 文件夹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的使用

你可能感兴趣的:(老男人开始学python之什么是模块、包、库?)