包的導入使用

在同一級目錄下新建 p1.py 和 run.py,添加代碼python

# p1.py 模塊的設計者
def f1(): print("from f1") def f2(): print("from f2") def f3(): print("from f3") # run.py 模塊的使用者
import p1 p1.f1() p1.f2() p1.f3()
View Code

假設後期須要添加許多功能,可能添加的功能與已有的功能之間還有關聯,這對於模塊的設計者是很不方便的,因而設計者建立多個文件,把相關的功能放入同一個文件,這裏我添加m1.py,m2.py,m3.py,將f1,f2,f3分別放入相關的功能文件app

# m1.py
def f1(): print("from f1") # m2.py
def f2(): print("from f2") # m3.py
def f3(): print("from f3")
View Code

但這樣對於使用者來講又不方便了,原先的使用方式當然已經改變,因而新建一個p1的文件夾,將m1.py,m2.py,m3.py放入p1,這樣對於使用者看起來仍是隻有一個模塊,使用的時候仍是p1.f1(),p1.f2(),p1.f3()等ide

之前導入的p1是一個模塊,如今導入的 p1 是一個文件夾(包),因而如今的問題是將這個包可以像以前的模塊同樣可以被導入和使用spa

1、什麼是包設計

包就是一個包含有 __init__.py 文件的文件夾,本質就是一種模塊,即包是用包導入使用的,包內部包含的文件也都是用來被導入使用3d

2、爲什麼要用包code

包是文件夾,那文件夾就是用來組織文件的blog

3、包的使用內存

首次導入包,發生三件事:博客

  一、以包下的 __init__.py 文件爲基準來產生一個名稱空間

  二、執行包下的 __init__.py 文件的代碼,將執行過程當中產生的名字都放入名稱空間中

  三、在當前執行文件中拿到一個名字,該名字就是指向__init__.py 名稱空間的

注意:

  一、在python3中,即便包下沒有 __init__.py 文件,import 包仍然不會報錯,而在python2中,包下必定要有該文件,不然import 包報錯

  二、建立包的目的不是爲了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包即模塊

新建包 p1 和 run.py,在包下新建 m1.py,在 m1.py 中添加代碼

# m1.py
def f1(): print('m1.f1')
View Code

如今我想在 run.py 中經過 p1.f1() 調用到 m1 中 f1 的功能,但此時是調用不到的,由於經過 p1 調用 f1 就是經過 __init__.py 調用 f1,__init__.py 中是沒有 f1 的,f1 是在 m1 中,因此要在 __init__.py 中導入 m1,首先不能直接 import m1,由於還須要拿到 m1 下的 f1 功能,因而可能有人會想,那我直接 from m1 import f1 就好了,但這樣也是不行的,由於內存中沒有 m1,內置模塊也沒有 m1,因而在 sys.path 中查找,sys.path 是以執行文件是 run.py 爲準,run.py 的 sys.path 的第一個值是上一級目錄,這個目錄中並無 m1 模塊(m1在p1中),因此直接 from m1 import f1 報錯

又有人會想,那我把 m1 模塊所在的文件夾(p1)添加到 sys.path 不就好了,因而我在 run.py(sys.path是以執行文件是run.py爲準)中添加環境變量

import sys sys.path.append(r'E:\Python\p1') import p1 p1.f1()
View Code

 這樣作確實可以實如今 run.py 中經過 p1.f1() 調用到 m1 中 f1 的功能,可是這對於使用者來講是很不方便的,每次都要添加內部功能所在文件夾的環境變量,因此這樣作也是不合適的。

能夠在 __init__.py 中以 p1.m1 的方式導入 f1,這樣在 run.py中就能夠直接導入 p1 而後 p1.f1() 執行

# __init__.py

from p1.m1 import f1 # run.py

import p1 p1.f1()
View Code

假設 run.py 和 p1 不在同一級目錄下,如今我新建一個 dir1,在 dir1 下新建一個 dir2,將 p1 放入 dir2,那這時在執行 run.py 時,就須要在 run.py 中添加環境變量了,有人可能有疑問,上面不是說添加環境變量不方便使用者嗎,注意,我在這裏添加的環境變量不是 p1 內部功能所在文件夾的環境變量,而是找到 p1 所在文件夾的環境變量,這就至關於用戶下載這個程序本身選擇的保存位置,在這個位置下能夠找到 p1。因此我在這裏只需將 dir2 的位置添加到環境變量便可

# run.py

import sys sys.path.append(r'E:\Python\dir1\dir2') import p1 p1.f1()
View Code

上面的導入也稱之爲絕對導入,每次都是參考執行文件的 sys.path 開始去導入 

 軟件每次更新都有不一樣的版本,設計者也須要將包更名,例如 p1_v1,p1_v2 等,若是使用的是絕對導入,那包內其它的導入都須要改變一次,因此包內的模塊不該該使用絕對導入,應該使用相對導入 

因此,在本片博客開始留下一個問題,將包像模塊同樣可以被導入和使用,因而在 p1 下新建一個 __init__.py 文件,使用相對導入

# __init__.py
from .m1 import f1 from .m2 import f2 from .m3 import f3
View Code

而後直接在 run.py 中導入 p1 即可以模塊同樣被使用

# run.py 模塊的使用者
import p1 p1.f1() p1.f2() p1.f3()
View Code

如今我在同一級目錄新建一個包 p1 和 run.py,在 p1 下新建包 p2,m1.py 和 m2.py,在包 p2 下新建 m3.py

  

# m1.py
def f1(): print('m1.f1') # m2.py
def f2(): print('m2.f2') # m3.py
def f3(): print('m3.f3')
View Code

如今仍是想實現與博客開始相同的功能,經過 p1.f1(),p2.f2(),p3.f3() 訪問功能,作法也與上面的相同,在 p1 的 __init__.py文件中導入相關模塊便可

# p1的__init__.py

from .m1 import f1 from .m2 import f2 from .p2.m3 import f3
View Code

如今我想在 m3.py 的 f3 中訪問到 f1 和 f2,因而在 m3 中須要導入 m1 和 m2

# m3.py

from ..m1 import f1 from ..m2 import f2 def f3(): print('m3.f3') f1() f2()
View Code

這時候即使 p1 更名 p1_v1,在 run.py 中導入調用 f3,包內的導入也無需更名

# run.py

import p1_v1 p1_v1.f3()
View Code

 

總結:

  1. 不管是 import 形式仍是 from...import 形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提升警覺:這是關於包纔有的導入語法,點的左邊都必須是一個包

  二、包的本質就是一個包含 __init__.py 文件的目錄,導入包就是在導包下的 __init__.py 文件

  三、若是使用絕對導入,絕對導入的起始位置都是以包的頂級目錄爲起始點。可是包內部模塊的導入一般應該使用相對導入,用一個點表明當前所在的文件(而非執行文件),兩個點表明上一級,須要強調的是,相對導入只能在包內部的模塊之間互相導入使用,使用多個點往上查找時不能超出頂級包

相關文章
相關標籤/搜索