Python模塊和包的詳細說明
-
模塊的導入
-
模塊的加載與修改
-
模塊和腳本的說明
-
模塊搜索路徑
-
包的導入
一、模塊的導入
之前我們簡單的使用了一下模塊,並沒有詳細的介紹,現在我們來詳細的說說
1.什么是模塊?
定義:邏輯上來說模塊就是一組功能的組合;實質上一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的后綴。
import加載的模塊分為四個通用類別:
a.使用python編寫的代碼(.py文件);
b.已被編譯為共享庫或DLL的C或C++擴展;
c.包好一組模塊的包
d.使用C編寫並鏈接到python解釋器的內置模塊;
2.如何使用模塊?
想要使用模塊,必須先要將模塊加載進來,可以通過關鍵字 import 或 from進行加載;需要注意的是模塊和當前文件在不同的命名空間中。
1)模塊的構成:
模塊可以包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第一次遇到導入import語句時才執行(import語句是可以在程序中的任意位置使用的,且針對同一個模塊很import多次,為了防止你重復導入,python的優化手段是:第一次導入后就將模塊名加載到內存了,后續的import語句僅是對已經加載大內存中的模塊對象增加了一次引用,不會重新執行模塊內的語句)
#我們先自定義一個模塊 名為mod.py; print("hello world") name = "zjk" def func1(): print("zjk1") def func2(): prpint("zjk2") func1() def func3(): print("zjk3") func2() #然后我們使用里一個py文件進行導入這個模塊; import mod import mod import mod import mod import mod -----------------------------打印輸出------------------------------------------ hello world #可以發現只打印了一次,是因為每次導入模塊時,解釋器都回去檢查一下這個模塊有沒有之前被導過。 例子
2)模塊導入的過程:
A.找到這個需導入的模塊;
B.判斷這個模塊是否被導入過;
如果沒有被導入過:
創建一個屬於這個模塊的命名空間;如果用戶沒有定義變量來引用這個模塊的內存地址的話,那么就使用模塊的名稱來引用這個模塊的內存地址;如果用戶使用as來指定變量接受這個內存地址的話,那么就將內存地址賦值給這個變量;且下文在調用時只能使用這個變量進行調用不能再使用模塊名進行調用了。然后執行這個模塊中的代碼;
如果該模塊已經被導入過:
那么解釋器不會重新執行模塊內的語句,后續的import語句僅僅是對已經加載到內存中的模塊的對象增加一次引用;
3)關於導入的模塊與當前空間的關系
帶入的模塊會重新開辟一塊獨立的名稱空間,定義在這個模塊中的函數把這個模塊的命名空間當做全局命名空間,這樣的話當前的空間就和模塊運行的空間分隔了,誰也不影響誰;
4)為模塊起別名
模塊在導入的時候開辟了新空間內存,默認是使用模塊的名稱來引用這個內存地址的,有時候模塊的名稱很長再加上執行調用里面的功能的時候,就顯的很不方便,為了更好的使用模塊,我們可以給模塊起別名;
也就是在導入模塊的時候我們不讓它使用默認的名字來引用內存地址,而是由我們自己定義的變量來引用這個模塊的內存地址;
方法:import my_module as mk
這樣的話就表示使用變量mk來引用這個內存地址,然后我們在文中再使用這個模塊的時候,只要使用mk來調用這個模塊里的功能即可。
還有一種好處是當有兩個模塊需要根據用戶的輸入來選擇使用的話,那么,用自定義變量來引用內存地址就再好不過了,例如:
#例如:join和pickle都有dump和dumps方法,根據用戶的輸入進行選擇使用哪一種 #第一種,不使用別名方式,使用默認的以模塊名引用的方式; def func(dic,t = 'json'): if t == 'json': import json return json.dumps(dic) elif t == 'pickle': import pickle return pickle.dumps(dic) #第二種,使用別名方式引用的內存地址; def func(dic, t='json'): if t == 'json': import json as aaa elif t == 'pickle': import pickle as aaa return aaa.dumps(dic) #可以看出使用別名的方式還是更好一些; 別名的好處
5)導入多個模塊
方法一:import os,time,sys,re 等等,每個模塊之間用逗號隔開;
方法二:import os
import time
import sys
方法二的好處就是當我們暫時不用某個模塊時直接注釋了就行,而方法一就得把那個模塊刪除;
多個模塊導入時的順序:
規范建議:模塊應該一個一個的導入,先后順序為:內置模塊---->擴展(第三方)模塊------>自定義模塊;
順序說明:我們知道導入模塊其實就是在執行這個模塊,我們不確定擴展模塊或自定義模塊里有沒有某個功能調用了內置模塊,所以,我們在導入模塊時,應先導入解釋器內置的模塊,然后在導入擴展模塊,最后導入自定義模塊。
小結:第一次導入后就將模塊名加載到內存了,后續的import語句僅是對已經加載大內存中的模塊對象增加了一次引用,不會重新執行模塊內的語句;導入模塊其實就是在執行py文件;開辟一塊新內容,將內容加載到內存中;
3. from.....import
我們在使用一個模塊時可能只想使用其中的某些功能,比如只想使用sys模塊中的modules時,那么import就不好用了,這時我們可以使用from.....import這樣的格式來進行模塊的某個功能的導入。
注意:這時模塊是已經全部加載了,但只是為這個功能進行了引用,其他的功能並沒有引用,所以在使用模塊的時候,就只能使用這個模塊的這個功能,其他的功能不能使用,如果想再使用這個模塊的另一個功能時,可以在進行一次模塊的要使用的功能的導入,這時模塊不會再進行加載了,而是只對該功能進行引用,這樣我們就可以使用這個功能了。
注意:導入某個功能時也可以為其進行變量引用。
#先看一下import能不能只導入模塊的某功能; import sys.module --------------------------打印輸出----------------------------------------------- Traceback (most recent call last): File "E:/python/zjk/模塊和包/模塊和包.py", line 1, in <module> import sys.module ModuleNotFoundError: No module named 'sys.module'; 'sys' is not a package #報錯告訴我們,沒有這個模塊,sys不是一個包,啥意思??這個問題我們稍后會在文中說明,為什么這樣不支持,包又是個啥。 #看一下from.....import 的使用 from sys import modules print(modules) -----------------------------打印輸出-------------------------------------------- {'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, #可以看出成功輸出,沒有報錯。 #再看一下使用as引用這個模塊的某個功能; from sys import modules as m print(m) ------------------------------打印輸出--------------------------------------- {'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, '_frozen_importlib': <module '_froze #這樣也是可以的 例子
強調一下python中的變量賦值都是對內存地址的引用,是一種綁定關系,因為我們操作的時候不可能直接拿內存地址來進行操作,所以就將內存地址和變量進行綁定,執行這個變量就相當於執行了這個內存地址中的內存;
from.....import 也支持as模式,這個我們在上個例子里也說過了,這里就不再重復了;
from.....import 也支持導入某個模塊的多個功能;如:
from os import (listdir,getcwd) #后面的擴號可加可不加,需要注意的是,這是向要導入下一個模塊就得另起一行了,不能在當前行導入;
from.....import *
* 表示導入模塊中所有的不是以下划線(_)開頭的名字都導入到當前位置,大部分情況下我們的python程序不應該使用這種導入方式,因為*你不知道你導入什么名字,很有可能會覆蓋掉你之前已經定義的名字。而且可讀性極其的差,在交互式環境中導入時沒有問題。
還有一點要說的是,如果使用* 的方式進行了導入,這時只想使用里面的某個或某些功能時,可以使用__all__來進行約束;
注意:__all__只是用來約束*方式的,其他方式導入的話,不會生效;具體使用見例子:
#首先我們看一下不約束時使用*的方式進行模塊導入; #准備了一個自定義模塊 mod.py print("hello world") name = "zjk" def func1(): print("zjk1") def func2(): print("zjk2") func1() def func3(): print("zjk3") func2() #在當前py中導入mod模塊; from mod import * print(name) func1() func2() func3() #調用mod模塊里的功能; ------------------------------------------------打印輸出--------------------- hello world zjk zjk1 zjk2 zjk1 zjk3 zjk2 zjk1 #可以看到,所有的功能和名字都可以被調用; #那么我們現在對其進行約束一下,要求只能使用fun3()功能; #我們在mod模塊開頭加入一下 __all__ = ["func3"] print("hello world") name = "zjk" def func1(): print("zjk1") def func2(): print("zjk2") func1() def func3(): print("zjk3") func2() #我們再次在當前py中進行調用; from mod import * func3() print(name) func1() func2() -----------------輸出結果--------------------------------------------------- hello world zjk3 zjk2 zjk1 Traceback (most recent call last): File "E:/python/zjk/模塊和包/模塊和包.py", line 3, in <module> print(name) NameError: name 'name' is not defined #可以看到只有func3執行成功了;為什么我要將func3放在最開頭呢?你知道了嗎? from import * 例子
4.模塊的循環引用的問題
先來看例子:
#有兩個文件進行相互調用; #文件1 mod1.py #內容: import mod print(123) def kkk(): print("kkk") mod.func1() #文件2 mod.py #內容: import mod1 print("hello world") kkk() name = "zjk" def func1(): print("zjk1") def func2(): print("zjk2") func1() def func3(): print("zjk3") func2() ##問題來了,當我運行mod1文件的時候會發生什么事??? ##我們看一下結果 ----------------------------打印輸出--------------------------------------- Traceback (most recent call last): File "E:/python/zjk/模塊和包/mod1.py", line 1, in <module> import mod File "E:\python\zjk\模塊和包\mod.py", line 1, in <module> import mod1 File "E:\python\zjk\模塊和包\mod1.py", line 5, in <module> mod.func1() AttributeError: module 'mod' has no attribute 'func1' #直接報錯了,有沒有想到原因呢? 循環引用問題