目錄
一、什么是包?
包是模塊的一種形式,包的本質就是一個含有.py的文件的文件夾。
二、為什么要有包?
模塊的第一個版本只有10個功能,但是未來在擴展版本的時候,模塊名和用法應該最好不要去修改,但是這只是對使用者友好,而由於版本擴展,文件越來越大,模塊設計者對模塊的管理、維護會越來越復雜,因此我們可以使用包來擴展模塊的功能。
三、如何用包?
3.1 模塊和包
導入模塊發生的三件事:
- 創建一個包的名稱空間
- 執行py文件,將執行過程中產生的名字存放於名稱空間中。
- 在當前執行文件中拿到一個名字aaa,aaa是指向包的名稱空間的
導入包發生的三件事:
- 創建一個包的名稱空間
- 由於包是一個文件夾,無法執行包,因此執行包下的.py文件,將執行過程中產生的名字存放於包名稱空間中(即包名稱空間中存放的名字都是來自於.py)
- 在當前執行文件中拿到一個名字aaa,aaa是指向包的名稱空間的
導入包就是在導入包下的.py,並且可以使用以下兩種方式導入:
- import ...
- from ... import...
3.2 擴展模塊功能

如下我們如果需要擴展aaa.py模塊,需要建立一個aaa的目錄文件,並且刪除aaa.py文件,將aaa.py修改成m1.py和m2.py兩個文件,讓模塊的功能使用方法不改變。
# aaa.py
def func1():
pass
def func2():
pass
def func3():
pass
def func4():
pass
def func5():
pass
def func6():
pass
# m1.py
def func1():
pass
def func2():
pass
def func3():
pass
# m2.py
def func4():
pass
def func5():
pass
def func6():
pass
# run.py
import aaa
aaa.func1()
aaa.func2()
aaa.func3()
aaa.func4()
aaa.func5()
aaa.func6()
3.3 修改__init__.py文件
# aaa/.py
func1 = 111
func2 = 222
func3 = 333
func4 = 444
func5 = 555
func6 = 666
由於在__init__.py中定義了func1,因此我們可以在run.py文件中導入func1,但是這個func1並不是我們想要的func1,因此需要修改__init__.py文件,又由於執行文件run.py的環境變量不為aaa,因此直接使用import導入m1會報錯,因此使用from導入。
# aaa/.py
from aaa.m1 import func1
from aaa.m2 import func2
# run.py
import aaa
print(aaa.func1())
print(aaa.func2())
3.4 導入包內包
aaa.bbb指向aaa內部的文件夾bbb包,如果我們需要導入bbb這個包。
# bbb/.py
from aaa import bbb
# run.py
import aaa
print(aaa.bbb)
3.5 導入包內包的模塊
如果bbb包內部有m3.py,我們需要從run.py導入m3模塊。
# bbb/.py
from aaa.bbb import m3
# run.py
import aaa
aaa.bbb.m3
3.6 絕對導入和相對導入
絕對導入:
# aaa/.py
from aaa.m1 import func1
from aaa.m2 import func2
相對導入:
- .代表當前被導入文件所在的文件夾
- ..代表當前被導入文件所在的文件夾的上一級
- ...代表當前被導入文件所在的文件夾的上一級的上一級
from .m1 import func1
from .m2 import func2
四、注意事項
- 包內所有的文件都是被導入使用的,而不是被直接運行的
- 包內部模塊之間的導入可以使用絕對導入(以包的根目錄為基准)與相對導入(以當前被導入的模塊所在的目錄為基准),推薦使用相對導入
- 當文件是執行文件時,無法在該文件內用相對導入的語法,只有在文件時被當作模塊導入時,該文件內才能使用相對導入的語法
- 凡是在導入時帶點的,點的左邊都必須是一個包,
import aaa.bbb.m3.f3錯誤

五、練習

假設我們有如上的目錄結構,文件內代碼如下:
# m1.py
def f1():
print('from f1')
# m2.py
def f2():
print('from f2')
# m3.py
def f3():
print('from f3')
1.如果我們需要在run.py中實現以下邏輯代碼,因此得在__init__.py文件中如此做:
# run.py
import aaa
aaa.f1()
aaa.f2()
aaa.f3()
print(aaa.bbb)
# aaa/__init__.py
from .m1 import f1
from .m2 import f2
from .bbb.m3 import f3
from . import bbb
2.如果我們需要在run.py中實現以下邏輯,__init__.py什么都不需要做:
# run.py
from aaa.bbb.m3 import f3
f3()
