1.模塊(Module)和包(Package) 1.1 理解模塊(Module) 理解為是一個py文件 module是組織單位,它自己獨立構成一個命名空間,它本身是一個Python object 在Python object裡面,還可以有很多其他的Python object 實際應用中, modul ...
1.模塊(Module)和包(Package)
1.1 理解模塊(Module)
理解為是一個py文件
module
是組織單位,它自己獨立構成一個命名空間,它本身是一個Python object
在Python object
裡面,還可以有很多其他的Python object
- 實際應用中,
module
對應的是py文件。
1.2 理解包(Package)
理解為一個文件夾
package
是一種特殊的modulepackage
幾乎和module
有一樣的功能,它只是多了一個path
- 區分
package
跟module
,是因為在操作系統層級,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.py
import sys
if __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.py
print('我是b.py')
##### a.py
import b
import sys
if __name__ == '__main__':
print(f"1.我是sys.modules: {dict(sys.modules.items())}")
print(f"2.列印模塊: {b}")
print('3.我是a.py')
運行結果
➜ python3 a.py
我是b.py
1.我是sys.modules: {...,'b': <module 'b' from '/Users/test_import/b.py'>}
2.列印模塊: <module 'b' from '/Users/test_import/b.py'>
3.我是a.py
3-3 導入模塊的object(from M import obj/func/var)
目錄
test_import # 頂層目錄
├── a.py
└── b.py
python文件
##### b.py
class B:
@staticmethod
def get_b():
print('我是b.py')
##### a.py
from b import B
import sys
if __name__ == '__main__':
print(f"1.我是sys.modules: {dict(sys.modules.items())}")
print(f"2.列印類: {B}")
print('3.我是a.py')
運行結果
➜ python3 a.py
我是b.py
1.我是sys.modules: {...,'b': <module 'b' from '/Users/test_import/b.py'>}
2.列印類: <class 'b.B'>
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
<module 'mypackage' (namespace)>
,只有namespace
目錄
test_import # 頂層目錄
├── a.py
└── mypackage
└── mymodule.py
python文件
##### a.py
import mypackage
if __name__ == '__main__':
print(mypackage)
print('我是a.py')
運行結果
➜ python3 a.py
<module 'mypackage' (namespace)>
我是a.py
4-1-2 有__init__.py
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
,指向具體的__init__.py
文件
目錄
test_import # 頂層目錄
├── a.py
└── mypackage
├── __init__.py
└── mymodule.py
python文件
##### mypackage/__init__.py
print('我是mypackage的__init__.py')
##### a.py
import mypackage
if __name__ == '__main__':
print(mypackage)
print('我是a.py')
運行結果
➜ python3 a.py
我是mypackage的__init__.py
<module 'mypackage' from '/Users/test_import/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.py
import mypackage
if __name__ == '__main__':
print(mypackage)
print(dir(mypackage))
print('我是a.py')
運行結果
<module 'mypackage' (namespace)>
['__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__.py
class B:
pass
##### a.py
import mypackage
if __name__ == '__main__':
print(mypackage)
print(dir(mypackage))
print('我是a.py')
運行結果
➜ python3 a.py
<module 'mypackage' from '/Users/test_import/mypackage/__init__.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.py
class Mym:
...
##### a.py
from mypackage import mymodule
if __name__ == '__main__':
# print(mypackage)
# print(dir(mypackage))
print(mymodule)
print(dir(mymodule))
print('我是a.py')
運行結果
➜ python3 a.py
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.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.py
class Mym:
...
##### a.py
from mypackage import mymodule
if __name__ == '__main__':
# print(mypackage)
# print(dir(mypackage))
print(mymodule)
print(dir(mymodule))
print('我是a.py')
運行結果
➜ python3 a.py
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.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.py
class Mym:
...
##### __init__.py
mymodule = '我是__init__里的mymodule'
##### a.py
from mypackage import mymodule
if __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.py
class Mym:
...
##### a.py
import mypackage.mymodule
if __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
<module 'mypackage' (namespace)>
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['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.py
class Mym:
...
##### a.py
import mypackage.mymodule
if __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
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['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.py
class Mym:
...
##### __init__.py
mymodule = '我是__init__里的mymodule'
##### a.py
import mypackage.mymodule
if __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
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['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.py
class Mym:
@staticmethod
def get_mym():
print('我是Mym的')
##### a.py
from mypackage.mymodule import Mym
if __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.py
class Mym:
@staticmethod
def get_mym():
print('我是Mym的')
##### mypackage/__init__.py
from .mymodule import Mym
##### a.py
from mypackage import Mym
if __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.py
from 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 c
c.run()
##### p2/p21/d.py
from p2.p22 import e
e.run()
##### a.py
from p1 import b
from 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 <module>
from p1.p11 import c
ModuleNotFoundError: No module named 'p1'
# 進入p1文件夾內運行也報錯
➜ python3 b.py
Traceback (most recent call last):
File "b.py", line 1, in <module>
from p1.p11 import c
ModuleNotFoundError: 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.py
Traceback (most recent call last):
File "./p2/p21/d.py", line 1, in <module>
from p2.p22 import e
ModuleNotFoundError: No module named 'p2'
# 進入p2/p21文件夾運行也報錯
➜ python3 python3 d.py
Traceback (most recent call last):
File "d.py", line 1, in <module>
from p2.p22 import e
ModuleNotFoundError: No module named 'p2'
# 使用python3 -m運行(因為是堂兄弟,所以要推到共同頂層外面執行,p2是共同的頂層)
➜ python3 -m p2.p21.d
我是e.py
6-2 相對導入
目錄結構和關係都沒有變,只在
b.py
和c.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 c
c.run()
##### p2/p21/d.py(改為相對導入)
from ..p22 import e
e.run()
##### a.py(主文件不能使用相對導入)
from p1 import b
from 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 <module>
from .p11 import c
ModuleNotFoundError: 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 <module>
from .p11 import c
ModuleNotFoundError: 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 <module>
from ..p22 import e
ValueError: attempted relative import beyond top-level package
# 進入p2/p21文件夾運行也報錯
➜ python3 d.py
Traceback (most recent call last):
File "d.py", line 1, in <module>
from ..p22 import e
ValueError: attempted relative import beyond top-level package
➜ python3 -m p2.p21.d
我是e.py
7.初步瞭解python3 -m
mod
是module
的縮寫,即-m
後面跟的是模塊(module
)名,意思是把模塊當成腳本來運行。
python3 -m package_name.py_file_name
,結尾不需要加.py
1.運行http.server
會把當前文件夾內的文件顯示在頁面上
➜ python3 -m http.server 8080
Serving 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 -