模塊的導入使用

1、什麼是模塊數據庫

模塊就是一系列功能的集合體,一個模塊就是一個包含了Python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。app

模塊有三種來源:spa

  一、內置的模塊3d

  二、第三方的模塊日誌

  三、自定義模塊code

模塊的四種通用類別:blog

  一、使用Python編寫的代碼(.py文件)內存

  二、已被編譯爲共享庫或DLL的C或C++擴展開發

  三、把一系列模塊組織到一塊兒的文件夾(注:文件夾下有一個__init__.py文件,該文件夾稱之爲包)字符串

  四、使用C編寫並連接到Python解釋器的內置模塊

2、爲什麼要用模塊

  一、使用內置的或者第三方模塊的好處是:拿來就可使用,能夠極大提高開發效率

  二、使用自定義模塊的好處是:能夠減小代碼冗餘(抽取咱們本身程序中要公用的一些功能定義成模塊,而後程序的各部分組件都去模塊中調用共享的功能)

3、模塊的使用

前提:必定要區分開誰是執行文件,誰是被導入模塊

一、import導入模塊

在Pycharm中右鍵新建一個文件,文件名是spam.py,模塊名是spam,再新建一個文件叫run.py,在run.py中

import spam

首次導入一個模塊,會發生如下事情:

  1)會產生一個模塊的名稱空間

  2)執行文件spam.py,將執行過程當中產生的名字都放到模塊的名稱空間中

  3)在當前執行文件的名稱空間中拿到一個模塊名,該名字指向模塊的名稱空間

以後的導入,都是直接引用第一次導入的成果,不會從新執行文件

在spam.py文件中添加代碼

money = 1000

def read1(): print('spam模塊:',money) def read2(): print('spam模塊') read1() def change(): global money money = 0

在執行文件中訪問模塊名稱空間中名字的語法:模塊名.名字,即在run.py中

import spam print(spam.money)   # 1000
print(spam.read1)   # <function read1 at 0x000001CE16209B70>
print(spam.read2)   # <function read2 at 0x000001CE16209A60>
print(spam.change)  # <function change at 0x000001CE16209C80>
spam.read1()    # spam模塊: 1000

def read1(): print('run.py --> read1') read1() # run.py --> read1
 spam.read2() # spam模塊
                # spam模塊: 1000
money = 9999 spam.change() print(spam.money)   # 0
print(money)        # 9999

總結 import 導入模塊:在使用時必須加上模塊名做爲前綴

優勢:指名道姓的向某一個名稱空間拿取名字,不會與當前名稱空間中的名字衝突

缺點:但凡應用模塊中的名字都須要加前綴,不夠簡潔

還能夠一行導入多個模塊,但不推薦使用

import spam, os, time

能夠爲模塊起別名(注意:模塊名應全爲小寫)

import spam as sm print(sm.money) print(sm.read1)

二、from...import...導入模塊

首次導入模塊發生的三件事:

  1)建立一個模塊的名稱空間

  2)執行文件spam.py,將執行過程當中產生的名字都放到模塊的名稱空間中

  3)在當前執行文件中直接拿到一個名字,該名字就是執行模塊中相對應的名字

刪除上面的兩個文件,從新建一個spam.py,添加代碼

money = 1000

def read1(): print('spam模塊:',money) def read2(): print('spam模塊') read1() def change(): global money money = 0

再新建一個run.py,在run.py中

from spam import money print(money)  # 1000
from spam import money money = 200  
print(money)  # 與當前名稱空間中的名字衝突, 結果爲200

總結from...import...導入模塊

優勢:使用時,無需再加前綴,更簡潔

缺點::容易與當前名稱空間中的名字衝突

如今將run.py裏的代碼改爲

from spam import money, read1 money = 200

# 這裏執行read1裏面的money仍是1000,由於在定義階段就已經固定死了,與調用位置無關
read1()         # spam模塊: 1000

print(money)    # 200

還能夠導入所有模塊,但不推薦使用

# 星號表明從被導入模塊中拿到全部名字
from spam import *

有一個 __all__ 的功能,將指定的模塊名以字符串的形式存放,若是再使用星號導入模塊,這時導入的就是 __all__裏面的內容,而不是導入所有的模塊,例如:

在spam.py中定義 __all__

__all__ = ['money', 'read1'] money = 1000

def read1(): print('spam模塊:',money) def read2(): print('spam模塊') read1() def change(): global money money = 0

在run.py中用星號導入

from spam import * read1() # spam模塊: 1000
read2()     # 報錯, 由於 __all__沒有包含read2模塊

能夠爲模塊起別名

from spam import read1 as r1 r1()

 4、Python文件的兩種執行方式

一、直接運行

二、做爲模塊導入

# 在m1.py中
def f1(): print('f1') print(__name__)    # 執行後是 __main__


# 在run.py中
import m1    # 執行後是 m1

即:當作腳本運行,__name__ 等於'__main__',當作模塊導入,__name__等於模塊名

因此這個條件是:if __name__ == '__main__': 用來控制.py文件在不一樣的應用場景下執行不一樣的邏輯

# 在m1.py中
def f1(): print('f1') if __name__ == '__main__': f1() # 在run.py中
import m1

5、模塊的搜索路徑

一、模塊搜索路徑的優先級

  1)內存中已經加載過的

  2)內置模塊

  3)sys.path(第一個值是當前執行文件所在的文件夾)

模塊搜索路徑優先從內存中已加載過的開始查找,例如我新建一個m1.py和一個run.py,在run.py中導入模塊m1

# m1.py
def f1(): print('from f1') # run.py
import time import m1 time.sleep(10)    # 程序睡眠10秒的過程當中刪除m1.py
import m1 m1.f1() # 這裏還能夠執行

 刪除m1.py文件後再導入執行不會報錯,由於在刪除的過程當中程序沒有結束,再次導入是優先從內存中查找,找到了直接運行,但若是再次運行就會報錯,由於內存已經回收,找不到m1模塊了

注意:不該該將本身的模塊名命名成與內置模塊或第三方模塊的名字相同

二、添加sys.path

新建m1.py和run.py,將m1.py放在dir1文件夾下,讓dir1文件夾和run.py在同一級目錄

# m1.py
def f1(): print('from f1')
f1()
# run.py import m1 # 這時候是找不到的,可是若是添加sys.path,將run.py改爲以下

# run.py import sys sys.path.append('E://Test//dir1') # 將m1所在的文件夾路徑添加到sys.path import m1

三、from...import...

仍是上面的狀況,能夠在run.py裏面經過from...import...導入

 

from dir1 import m1

這是在sys.path中找到的,可是我沒有添加sys.path,爲何也能找到呢?

由於sys.path的第一個值是當前執行文件所在的文件夾,也就是Test文件夾(個人run.py和dir1的上一層是Test文件夾),因此說是以當前執行文件的sys.path爲準,能夠找到dir1,進而找到m1

基於上面的目錄,我在dir1下新建一個文件夾叫dir2,在dir2中新建一個文件叫m2.py,如今的路徑關係是:Test下面有一個run.py和dir1,dir1下有一個m1.py和dir2,dir2下有一個m2.py

m2中添加代碼

def f2(): print('from f2')
f2()

能夠經過from...import...導入

from dir1.dir2 import m2

 第一種特殊狀況:模塊的絕對導入

刪除上面的全部文件,新建run.py和dir1文件夾,在dir1下新建m1.py和m2.py

# m1.py
def f1(): print('from f1') # m2.py
def f2(): print('from f2')

run想訪問m1,由於不在同一級目錄,因此要經過上面講到的兩種方法(添加sys.path或from...import導入)來訪問(我用後者)

# run.py
from dir1 import m1

如今我執行run.py,能夠經過run訪問到m1

如今m1想訪問m2,只須要在m1中導入m2便可

# m1.py
import m2 def f1(): print('from f1') m2.f2()

可是如今,我再執行run.py,可否經過run訪問到m1再訪問到m2呢?

不行!由於sys.path是以當前執行文件爲準的,那麼sys.path的第一個值就是 E://Test//,在m1裏面導入m2的時候,去sys.path中沒法找到m2,因此會報錯

強調:全部被導入的模塊參照的環境變量sys.path都是以執行文件爲準的

那麼怎麼解決呢

# m1.py
from dir1 import m2 def f1(): print('from f1') m2.f2() # m2.py
def f2(): print('from f2') # run.py
from dir1 import m1 m1.f1()

注意:不要理解成sys.path是以執行文件所在的文件夾爲準,由於sys.path有不少個值,而執行文件所在的文件夾僅僅只是sys.path中的一個值,這個執行文件所在的文件夾找不到後面還有不少值能夠找

上面這種狀況是以執行文件的sys.path做爲參考點開始導入,稱之爲模塊的絕對導入

優勢:在執行文件與被導入的模塊中均可以使用

缺點:全部導入都是以sys.path爲參考點,導入麻煩

第二種特殊狀況:模塊的相對導入

參照當前所在文件的文件夾爲起始開始查找,稱之爲模塊的相對導入

符號:.(一個點)表明當前所在文件的文件夾,..(兩個點)表明上一級文件夾,...(三個點)表明上一級的上一級文件夾

優勢:導入更加簡單

缺點:只能在被導入的模塊中使用,不能在執行文件中用

如今在Test下新建一個dir0,dir0下新建一個dir1和run.py,dir1下新建m1.py和m2.py

# run.py
from dir0.dir1 import m1    # 用的仍是絕對導入
 m1.f1() # m1.py
from . import m2    # 用的是相對導入

def f1(): print('from f1') m2.f2() # m2.py
def f2(): print('from f2')

 6、軟件開發的目錄規範

以 「ATM+購物車」 舉例

ATM + 購物車 bin: 整個程序的執行文件,入口(調用核心邏輯的一些功能) - start.py conf: 配置文件(程序組件共用的變量) - settings.py lib: 庫(自定義的模塊, 程序組件共用的功能) - common.py core: 核心邏輯(與業務相關的邏輯, 購物車的登陸註冊轉帳取款等) - src.py log: 日誌(程序運行產生的關鍵信息記錄) - transaction.log db: 數據(數據庫相關的文件) Readme: 讀我(軟件的介紹, 說明書)

調用業務相關的邏輯應該經過start.py去調取src模塊,因此要添加環境變量,而後在start.py中添加代碼

# run.py

import sys sys.path.append(r'E:\Python\ATM\core') import src src.run()

雖然添加core可以讓start.py調取到src模塊,但可不能這麼作。由於之後別人做爲軟件的使用者,下載了這個軟件而後使用,但這裏添加的環境變量是開發者本身機器上的文件路徑,別人使用時和我確定不是同樣的文件路徑,因此沒法使用。這時須要讓使用者不管在哪一個路徑下都能使用這個軟件,因此要添加一個通用的環境變量,具體作法是添加整個項目的根文件夾。可是這裏可不能又寫我硬盤上的文件路徑,而是讓程序本身獲取整個項目的根文件夾。

# run.py

print(__file__) # 運行
E:/Python/ATM/bin/start.py

__file__能夠獲取當前執行文件的絕對路徑,不一樣的機器能夠獲取不一樣的絕對路徑。如今須要獲取執行文件所在文件夾的父級文件夾,因此能夠基於__file__來獲取

os模塊有個功能能夠獲取當前執行文件所在的文件夾的路徑

# run.py

import os print(os.path.dirname(__file__)) # 運行
E:/Python/ATM/bin

那麼基於上面獲取父級文件夾就是再使用一個os.path.dirname

# run.py

import os print(os.path.dirname(os.path.dirname(__file__))) # 運行
E:/Python/ATM

這時便獲取到了執行文件所在文件夾的父級文件夾,而後添加到環境變量,之後不管這個軟件在哪臺機器上運行,均可以獲得精準的目錄

# run.py

import os import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import src src.run()

有一個標準的寫法,是將if __name__ == '__main__': 添加進去

# run.py

import os import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import src if __name__ == '__main__': src.run()
相關文章
相關標籤/搜索