您好,登錄后才能下訂單哦!
在Python中,使用import關鍵字導入一個包或者模塊,模塊是一個名為module
的類型,只有模塊類型才可以直接使用import導入。首先是導包過程。
print('導入前:', dir()) # 導包前全局變量
import os
print('導入后:', dir()) # 導包后全局變量
-----輸出結果-----#省略
導入前:全局變量中沒有"os"
導入后:出現了"os"
這說明全局變量中出現了os
標識符,這也是我們為什么可以使用os.chdir()
等通過os
標識符進行成員訪問的原因。
再看一下os
標識符的類型及os
指向的這個對象。
print(type(os))
print(type(os.path))
print(global()["os"]) # 收集全局變量,查看os對象信息
-----輸出結果-----
<class 'module'>
<class 'module'>
<module 'os' from 'E:\\Python\\lib\\os.py'>
上面結果顯示os
和os.path
是一個module
類型,這也是os
可以使用import
導入的原因。只有module
類型才能被導入。同理os.path
也可以直接被導入。
print(dir())
import os.path
print(dir())
-----輸出結果-----#省略
導入前:全局變量中沒有"os" 或者 "os.path"
導入后:出現了"os",但是沒有"os.path"
os.path并不是一個合法的標識符(字符,下劃線,數字),所以這個os.path
對象沒有被變量接受,但是我們之后需要能訪問這個os.path
對象 ,所以python為我們保留了os
變量指向os
模塊。我們才可以使用os.path
的方式訪問。當然我們使用別名的方式os.path就可以被接收了。
import os.path as osp
osp.dirname(".") # osp 即指向 os.path模塊對象.調用它全局空間中的dirname(".")函數
print(type(osp)) # <class 'module'>
print(globals()["osp"]) # <module'ntpath'from'E:\\Python\\lib\\ntpath.py'>
osp
直接指向了我們需要os.path模塊,我們可以osp
進行訪問,os
變量也就沒有意義,所以此時的全局變量總并不存在os
這個全局變量,但是os
這個模塊確實被import
加載到內存空間中。只是在該模塊中沒有對應的表示符進行對應。
在sys.path
中記錄了模塊的所有順序,并且可以程序執行時候,導入了哪些類,所有被導入的類都會緩存在sys.modules
中,調用即可查看。
import sys
print(*sys.path, "\n", *sys.modules, sep="\n")
--------輸出結果------
'''
D:\學習資料\練習項目\pycharm基礎練習\myproject # 當前路徑
D:\學習資料\練習項目\pycharm基礎練習 # pycharm 創建的項目環境
E:\Python\python36.zip # 以下為Python安裝路徑下的各個路徑,可以為zip,egg文件
E:\Python\DLLs
E:\Python\lib
E:\Python
E:\Python\lib\site-packages
'''
{'builtins': <module 'builtins' (built-in)>, # 已經被導入的各個模塊信息
'sys': <module 'sys' (built-in)>,
'os': <module 'os' (built-in)>,
'_frozen_importlib': <module 'importlib._bootstrap'
...
'_tracemalloc': <module '_tracemalloc' (built-in)>,
'myproject': <module 'myproject' (namespace)>}
.egg
文件是由setuptools
庫創建的包,第三方庫常用的格式,添加了元數據信息的zip
文件。
from ... import ...
從一個模塊中導入對象,這個模塊可能是一個.py文件也可能是一個包(目錄),導入的對象可以是包或者模塊下的函數,類,模塊等全局變量標識符,并且導入后可以直接使用import
后的原變量標識符進行訪問,而不需要加上模塊前綴。from
和import
后指定的內容都將被加載到內存。
from os import path # 從os 導入 path模塊,并可以使用path全局變量直接訪問
from os.path import dirname # 從os.path 模塊導入 dirname方法,可以直接通過dirname標識符訪問該方法對象。
from os.path import * # 默認從os.path模塊導入所有公共變量(非下劃線開頭),并直接使用原變量名作為該包下的全局變量
使用第三種方式容易造成該包中的全局變量被導入包中全局變量覆蓋。除非清楚的知道兩個包中的變量不會重名,否則盡量不使用。
使用 from ... import *
默認導入的是公開變量(非_
或__
打頭的變量),非公開變量導入必須手動才能訪問,或者添加到all屬性中才能使用*導入
from os import _abc, __abc # 直接指定可導入,* 默認不含該類屬性
在被導入模塊中,可以添加__all__
屬性來指定該模塊默認的全部可向外導出的模塊。配合from ...import *
使用。__all__
屬性是一個字符串列表,這些字符串必須與該全局空間中的全局變量名對應,或者與該包下的子包名對應。
__all__ = ["x", "y", "_z"]
x = 1
y = 2
z = 3
_z = 4
這個包被其他包使用 *導入時,導出__all__
中對應的x
, y
,_z
變量,實現了我們手動控制變量的導出。
包導入時屬性優先,沒有這個屬性才會判斷是否有這個模塊。所以如果屬性名和模塊名沖突,該模塊將無法再被導出。
Python中的包就是一個文件夾,文件夾下放各個模塊的.py文件或者一個子包,方便管理。在包上也是可以寫代碼,這就是需要這個包下的__init__.py
文件,這個文件屬于這個包,當我們僅僅導入一個包時候,就是導入這個包下的__init__.py
文件中的全局變量所指定的內容。并不會自動的導入這個包下的子模塊。
包模塊的代碼托管到包下的__init__.py
文件中,即使包沒有__init__
文件仍然可以被導入,但并沒有導入任何內容,這種情況下只能通過這個包名去尋找這個包下的模塊文件。使用from ... inport ...
導入子模塊中的內容。
包是一個稍微特殊的模塊對象,包的屬性有['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
,根據__package__
屬性可以判斷它是否是一個包,該屬性為None或者不存在表示不是包。
包下的模塊為這個包的子模塊,他們之間可以通過package.mod_name
進行訪問,前提是這個模塊已經被導入,可以使用from package import mol_name或者import package.mol_name進行導入,兩種導入效果相同,只是導入空間的變量名不同,使用形式不同。但是只import package
無法自動導入它的子包,package.mul_name
將不能訪問。
使用import導入模塊順序在sys.module
記錄,默認優先從執行文件的當前目錄中尋找,無法找到再去Python安裝文件中的庫中尋找。這是一種絕對路徑導入。
相對導入通常在一個包中使用,方便的將包中的各個模塊進行關聯,這種關聯只受包內文件的相對位置約束,然而對于一個包我們通常不會去干涉內部的文件關系。相對導入原則遵循文件系統使用原則,即使是包__init__.py
文件,這時屬于這個包下的一個子文件,等同于這個包下的其他子文件。
符號 | 示例 | |
---|---|---|
. | .m | 當前文件夾中的m模塊 |
.. | ..m | 上一級文件中的m模塊 |
... | ...m | 上上一級文件中的m模塊 |
from .m import a # 將會在當前目錄下找 m 文件并導入a
from ..m import a # 訪問該文件的上一層目錄找 m 文件并導入a
from .m.m1 import a # 當前文件所在目錄中的m包下的 m1文件并導入a
以上導入方式只能在包中使用,(任何一個相對導入的路徑不能涉及主包所處的當前目錄)這些文件不能作為主模塊直接運行,它是一種包內部的關系的建立方式,直接運行將報錯。
當我們導入一個模塊時,我們可以訪問這個模塊是因為在當前的作用域內部,創建了一個與模塊名同名的全局變量,才可以通過這個全局變量對這個模塊進行訪問。所以我們是否能使用一個模塊,需要兩個條件:
不同的導入文件方式在這個命名空間中創建的標識符是不同的
import os # 只導入os模塊(os下的__init__.py中的內容),創建os標識符
import os as o # 只導入os模塊,創建o標識符
import os.path # 同時導入os 和 os.path,只創建 os標識符,指向os模塊。os.path可訪問
import os.path as osp # 同時導入os 和 os.path,只創建 osp標識符,指向os.path模塊,os模塊在內存,但是無法訪問,無標識符
from os import path # 同時導入os 和 os.path,只創建path標識符,指向os.path。os無法訪問,無標識符
from os import * # 同時導入os中所有公開變量,如果有__all__屬性,導入指定的內容,創建所有 * 指代的標識符,不會創建os
form .m import a # 在包內導入, m 和 a 均導入,m標識符可能存在,可使用 dir查看確認再使用,a 標識符存在
模塊命名規范:
在導入模塊時,會使用模塊名作為標識符,這就要求模塊名滿足標識符的命名規范,這樣才可以被導入。并且模塊一幫使用小寫字符,可以使用下劃線分割。
模塊被加載一次后會在內存中緩存這個模塊對象,這個模塊的辨識信息被緩存到sys.modules
中。導入模塊時候,首先是從sys.modules
中查詢該模塊是否已經被加載,如果已存在,并不會從文件中讀取,而是直接使用內存中已存在的這個模塊對象,否則import會IO搜索該模塊的文件,編譯,執行這個模塊并加載大內存。
緩存的模塊被保存在sys.module中,包括自己,其中還包括解釋器運行需要的模塊。
自定義模塊a/b/c
路徑,如果只導入a模塊import a
,直接使用a.b
是有風險的,該模塊沒有被加載,只有使用import
關鍵字時,解釋器才會模塊進行加載,而不會自動的加載。
當我們執行一個.py文件,此時解釋器會啟動去執行,但在執行這個文件之前,解釋器還需要其他的工作,比如導入一些包,例如io
,將我們的.py文件讀入內存,或者build-in
,因為我們可能使用到了這個內建函數。還有其他很多準備流程,當這個工作完成后,才會執行我們自己的.py文件。而這個.py文件也會被命名為__main__
包。查看這個模塊名,顯示為__main__
print(__name__) # __main__
除解釋器執行的代碼外,這個模塊將會作為最外層的代碼塊,這個模塊的結束代表該線程的結束。也被稱作頂層代碼。頂層代碼包的"name"屬性為__main__
,其余模塊的__name__
屬性為模塊名。所以測試代碼通常這樣寫
if __name__ == "__main__":
# test code
只有這個模塊直接執行時,if
中的測試代碼才會執行。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。