1.模块(Module)和包(Package)

1.1 理解模块(Module)

理解为是一个py文件

  • module是组织单位,它自己独立构成一个命名空间,它本身是一个Python object
  • 在Python object里面,还可以有很多其他的Python object
  • 实际应用中, module对应的是py文件。

1.2 理解包(Package)

理解为一个文件夹

  • package是一种特殊的module
  • package 几乎和 module 有一样的功能,它只是多了一个path
  • 区分packagemodule,是因为在操作系统层级,package往往对应的是一个文件夹(可以有其他的文件夹或者有文件)
  • package里面儿可以有其它的包(subpackage),也可以有模块(module)

2. import都做了哪些事情

  • 1.查找模块文件(通过sys.path可以查看目录的导入顺序)
    • 程序主目录
    • PYTHONPATH 目录
    • 标准链接库目录
  • 2.编译成位码(即pyc文件)
  • 3、执行模块的代码来创建其所定义的变量
    • 导入时,代码是会执行的

3.导入模块(Module)3-1 查看sys.path目录

如果自定义包没在目录里,可以往目录中添加搜索路径sys.path.append(path)

搜索是从上往下查找,如果中间查到某个包就不会往下查询,尽量把自定义包插入到前面sys.path.insert(0,path)

test_import # 顶层目录└── a.py
##### a.pyimport sysif __name__ == '__main__':  print(sys.path)
[  '/Users/test_import',# 当前执行py文件所在的文件夹  '/local/Python3/3.8/lib/python38.zip',  '/local/Python3/3.8/lib/python3.8',  '/local/Python3/3.8/lib/python3.8/lib-dynload',  '/local/Python3/3.8/lib/python3.8/site-packages'# pip install的位置]

3-2 导入时代码执行

导入模块/包时,会运行代码把它加载到sys.modules缓存起来。

目录

test_import # 顶层目录├── a.py└── b.py

python文件

##### b.pyprint('我是b.py')##### a.pyimport bimport sysif __name__ == '__main__':  print(f"1.我是sys.modules: {dict(sys.modules.items())}")  print(f"2.打印模块: {b}")  print('3.我是a.py')

运行结果

➜  python3 a.py 我是b.py1.我是sys.modules: {...,'b': }2.打印模块: 3.我是a.py

3-3 导入模块的object(from M import obj/func/var)

目录

test_import # 顶层目录├── a.py└── b.py

python文件

##### b.pyclass B: @staticmethod def get_b():   print('我是b.py')##### a.pyfrom b import Bimport sysif __name__ == '__main__':  print(f"1.我是sys.modules: {dict(sys.modules.items())}")  print(f"2.打印类: {B}")  print('3.我是a.py')

运行结果

➜  python3 a.py 我是b.py1.我是sys.modules: {...,'b': }2.打印类: 3.我是a.py

4.引入包(Package)

在import一个Package会查看Package下面有没有__init__.py文件,没有的话不会运行额外的代码,有的话运行__init__.py

运行__init__.py文件,实际上是开辟了单独的命名空间存放文件内容,然后用这个命名空间来构成一个module(特殊的module)

4-1 查看包信息(import P)4-1-1 无__init__.py

,只有namespace

目录

test_import # 顶层目录├── a.py└── mypackage    └── mymodule.py

python文件

##### a.pyimport mypackageif __name__ == '__main__':  print(mypackage)  print('我是a.py')

运行结果

➜  python3 a.py我是a.py

4-1-2 有__init__.py

,指向具体的__init__.py文件

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mypackage/__init__.pyprint('我是mypackage的__init__.py')##### a.pyimport mypackageif __name__ == '__main__':  print(mypackage)  print('我是a.py')

运行结果

➜  python3 a.py我是mypackage的__init__.py我是a.py

4-2 查看包有没有引入模块(import P)

import package时,查看包下面的模块有没有被导入

4-2-1 无__init__.py

dir(mypackage)中没有mymodule的命名空间

目录

test_import # 顶层目录├── a.py└── mypackage    └── mymodule.py

python文件

##### a.pyimport mypackageif __name__ == '__main__':  print(mypackage)  print(dir(mypackage))  print('我是a.py')

运行结果

['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']我是a.py

4-2-2 有__init__.py

dir(mypackage)mymodule的命名空间

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mypackage/__init__.pyclass B:  pass##### a.pyimport mypackageif __name__ == '__main__':  print(mypackage)  print(dir(mypackage))  print('我是a.py')

运行结果

➜  python3 a.py['B', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']我是a.py

4-3 从包中导入模块(import P from M)4-3-1 无__init__.py

想查看mypackage信息就查看不了了

目录

test_import # 顶层目录├── a.py└── mypackage    └── mymodule.py

python文件

##### mymodule.pyclass Mym:  ...  ##### a.pyfrom mypackage import mymoduleif __name__ == '__main__':  # print(mypackage)  # print(dir(mypackage))  print(mymodule)  print(dir(mymodule))  print('我是a.py')

运行结果

➜  python3 a.py['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']我是a.py

4-3-2 有__init__.py(无内容)

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mymodule.pyclass Mym:  ...  ##### a.pyfrom mypackage import mymoduleif __name__ == '__main__':  # print(mypackage)  # print(dir(mypackage))  print(mymodule)  print(dir(mymodule))  print('我是a.py')

运行结果

➜  python3 a.py['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']我是a.py

4-3-3 有__init__.py(有内容)

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mymodule.pyclass Mym:  ...  ##### __init__.pymymodule = '我是__init__里的mymodule'##### a.pyfrom mypackage import mymoduleif __name__ == '__main__':  # print(mypackage)  # print(dir(mypackage))  print(mymodule)  print(dir(mymodule))  print('我是a.py')

运行结果

➜  python3 a.py             我是__init__里的mymodule[..., 'center', 'count', 'encode', 'endswith', ...]我是a.py

4-4 直接导入(import P.M)

import mypackage.mymodule时,单独使用mymodule会报错NameError: name 'mymodule' is not defined

必须mypackage.mymodule一起使用

4-4-3 无__init__.py

目录

test_import # 顶层目录├── a.py└── mypackage    └── mymodule.py

python文件

##### mymodule.pyclass Mym:  ...##### a.pyimport mypackage.mymoduleif __name__ == '__main__':  print(mypackage)  print(dir(mypackage))  # print(mymodule)# 报错  # print(dir(mymodule))# 报错  print(mypackage.mymodule)  print(dir(mypackage.mymodule))  print('我是a.py')

运行结果

➜  python3 a.py['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']我是a.py

4-4-3 有__init__.py(无内容)

效果和没有__init__.py执行是一样的

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mymodule.pyclass Mym:  ...##### a.pyimport mypackage.mymoduleif __name__ == '__main__':  print(mypackage)  print(dir(mypackage))  # print(mymodule)# 报错  # print(dir(mymodule))# 报错  print(mypackage.mymodule)  print(dir(mypackage.mymodule))  print('我是a.py')

运行结果

➜  python3 a.py['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']我是a.py

4-4-3 有__init__.py(有内容)

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mymodule.pyclass Mym:  ...  ##### __init__.pymymodule = '我是__init__里的mymodule'##### a.pyimport mypackage.mymoduleif __name__ == '__main__':  print(mypackage)  print(dir(mypackage))  # print(mymodule)  # print(dir(mymodule))  print(mypackage.mymodule)  print(dir(mypackage.mymodule))  print('我是a.py')

运行结果

➜  python3 a.py['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']我是a.py

5.关于__init__.py

在python3中,文件夹下无论有没有__init__.py文件,这个文件夹都可以作为一个包(Package)被python使用

可以存放和普通模块一样的代码(量、类、函数..)

__init__.py中使用相对导入

5-1 简化import语法5-1-1 无__init__.py

需要指名道姓的支出使用哪个obj/func/var

目录

test_import # 顶层目录├── a.py└── mypackage    └── mymodule.py

python文件

##### mypackage/mymodule.pyclass Mym:  @staticmethod  def get_mym():    print('我是Mym的')##### a.pyfrom mypackage.mymodule import Mymif __name__ == '__main__':  Mym().get_mym()

运行结果

➜  python3 a.py我是Mym的

5-1-2 有__init__.py

from p.x.x.x.m import obj转变为from p import obj的效果

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mypackage/mymodule.pyclass Mym:  @staticmethod  def get_mym():    print('我是Mym的')##### mypackage/__init__.pyfrom .mymodule import Mym##### a.pyfrom mypackage import Mymif __name__ == '__main__':  Mym().get_mym()

运行结果

➜  python3 a.py我是Mym的

5-2 批量导入和规范化导入以及__all__

用于管理导出的方法,只在from p import *是生效

有效: __init__.py使用from m import * 同时a.py使用from p import *时才生效

无效: __init__.py使用from m import *a.py使用from p import fun3那么会绕开__all__设置的规则, 可以直接使用fun3

目录

test_import # 顶层目录├── a.py└── mypackage    ├── __init__.py    └── mymodule.py

python文件

##### mypackage/mymodule.py def fun1():  print('我是fun1')def fun2():  print('我是fun2')def fun3():  print('我是fun3')##### mypackage/__init__.py from .mymodule import *__all__ = ['fun1', 'fun2']##### a.pyfrom mypackage import *if __name__ == '__main__':  fun1()  fun2()  # fun3() 报错NameError: name 'fun3' is not defined

运行结果

➜  python3 a.py我是fun1我是fun2

6.绝对导入和相对导入6-1 绝对导入

目录

test_import # 顶层目录├── a.py# 引用了b.py和c.py[子孙关系]├── p1│   ├── b.py     # 引用了c.py[长辈关系]│   └── p11│       └── c.py # 有一个def run():print('我是c.py')└── p2    ├── p21    │   └── d.py # 引用了e.py[堂兄弟关系]    └── p22        └── e.py # 有一个def run():print('我是e.py')

文件内容

##### p1/b.py from p1.p11 import cc.run()##### p2/p21/d.py from p2.p22 import ee.run()##### a.pyfrom p1 import bfrom p2.p21 import d

6-1-1 绝对-运行主文件(a.py)

➜  python3 a.py我是c.py我是e.py

6-1-2 绝对-运行子包下面的模块(b.py)

# 在test_import文件夹内调用b.py➜  python3 p1/b.py Traceback (most recent call last):  File "p1/b.py", line 1, in     from p1.p11 import cModuleNotFoundError: No module named 'p1'# 进入p1文件夹内运行也报错➜  python3 b.py Traceback (most recent call last):  File "b.py", line 1, in     from p1.p11 import cModuleNotFoundError: No module named 'p1'# 使用python3 -m运行(b.py顶层外面执行,p1是共同的顶层)➜  python3 -m p1.b我是c.py

6-1-3 绝对-运行子包下面的模块(d.py)

# 在test_import文件夹内调用d.py➜  python3 ./p2/p21/d.pyTraceback (most recent call last):  File "./p2/p21/d.py", line 1, in     from p2.p22 import eModuleNotFoundError: No module named 'p2'# 进入p2/p21文件夹运行也报错➜  python3 python3 d.py Traceback (most recent call last):  File "d.py", line 1, in     from p2.p22 import eModuleNotFoundError: No module named 'p2'# 使用python3 -m运行(因为是堂兄弟,所以要推到共同顶层外面执行,p2是共同的顶层)➜  python3 -m p2.p21.d我是e.py

6-2 相对导入

目录结构和关系都没有变,只在b.pyc.py绝对引入改为相对引入

注意: 入口文件(a.py)不能使用相对引入其他模块,必须为绝对引入

目录

test_import # 顶层目录├── a.py# 引用了b.py和c.py[子孙关系]├── p1│   ├── b.py     # 引用了c.py[长辈关系]│   └── p11│       └── c.py # 有一个def run():print('我是c.py')└── p2    ├── p21    │   └── d.py # 引用了e.py[堂兄弟关系]    └── p22        └── e.py # 有一个def run():print('我是e.py')

文件内容

##### p1/b.py(改为相对导入)from .p11 import cc.run()##### p2/p21/d.py(改为相对导入)from ..p22 import ee.run()##### a.py(主文件不能使用相对导入)from p1 import bfrom p2.p21 import d

6-2-1 相对-运行主文件(a.py)

➜  python3 a.py我是c.py我是e.py

6-2-2 相对-运行子包下面的模块(b.py)

# 在test_import文件夹内调用b.py➜  python3 p1/b.py Traceback (most recent call last):  File "p1/b.py", line 1, in     from .p11 import cModuleNotFoundError: No module named '__main__.p11'; '__main__' is not a package# 进入p1文件夹内运行也报错➜  python3 b.py Traceback (most recent call last):  File "b.py", line 1, in     from .p11 import cModuleNotFoundError: No module named '__main__.p11'; '__main__' is not a package# 使用python3 -m运行(b.py顶层外面执行,p1是共同的顶层)➜  python3 -m p1.b我是c.py

6-2-3 相对-运行子包下面的模块(d.py)

# 在test_import文件夹内调用d.py➜  python3 ./p2/p21/d.py Traceback (most recent call last):  File "./p2/p21/d.py", line 1, in     from ..p22 import eValueError: attempted relative import beyond top-level package# 进入p2/p21文件夹运行也报错➜  python3 d.py  Traceback (most recent call last):  File "d.py", line 1, in     from ..p22 import eValueError: attempted relative import beyond top-level package➜  python3 -m p2.p21.d我是e.py

7.初步了解python3 -m

modmodule的缩写,即-m后面跟的是模块(module)名,意思是把模块当成脚本来运行。

python3 -m package_name.py_file_name,结尾不需要加.py

1.运行http.server

会把当前文件夹内的文件显示在页面上

➜  python3 -m http.server 8080Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...127.0.0.1 - - [22/Mar/2023 23:56:18] "GET / HTTP/1.1" 200 -127.0.0.1 - - [22/Mar/2023 23:56:20] "GET /p1/ HTTP/1.1" 200 -127.0.0.1 - - [22/Mar/2023 23:56:22] "GET /p1/p11/ HTTP/1.1" 200 -127.0.0.1 - - [22/Mar/2023 23:56:28] "GET /p2/ HTTP/1.1" 200 -