Python 模組
1. 模組簡介
1.1 什麼是模組
編寫較長程式時,建議用文字編輯器代替直譯器,執行檔案中的輸入內容,這就是編寫 指令碼 。隨著程式越來越長,為了方便維護,最好把指令碼拆分成多個檔案。編寫指令碼還一個好處,不同程式呼叫同一個函式時,不用每次把函式複製到各個程式。為實現這些需求,Python 把各種定義存入一個檔案,在指令碼或直譯器的互動式例項中使用。這個檔案就是 模組
模組即是一系列功能的結合體。
1.2 為什麼使用模組
提高了程式碼的可維護性,不用重複造輪子
提升開發效率.
1.3 模組的各類
- 內建模組(使用
python
直譯器直接可以匯入) - 第三方模組(使用
pip
安裝) - 自定義
1.4 模組的表現形式
-
使用python編寫的程式碼(.py檔案),就是平時寫的一個python檔案
-
已被編譯為共享庫或DLL的C或C++擴充套件
-
包好一組模組的包(資料夾)
包其實就是多個py檔案(模組)的集合
包裡面通常會含有一個
__init__.py
檔案(在python3中這個檔案可以沒有) -
使用C編寫並連結到python直譯器的內建模組
2. import句式
匯入模組使用關鍵字import
加py
檔名,不要加.py
.
示例:
# 匯入內建模組
>>> import time
>>> time.time() # 直接使用
1637651203.9467623
#匯入自定義
# 程式碼檔案:foo.py
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
# 匯入
>>> import foo
>>> foo.
foo.hello( foo.name
>>> foo.name
'Hans'
>>> foo.hello(foo.name)
Hello, Hans
>>> foo.hello("Jack")
Hello, Jack
# 同一個模組多次匯入
# 程式碼檔案:boo.py
print("hello")
# 匯入
>>> import boo # 第一次匯入,會執行裡面的程式碼。
hello
>>> import boo # 第二次匯入,不會執行
>>> import boo # 第二次匯入,不會執行
>>> import boo # 第二次匯入,不會執行
# 多次匯入相同模組 只會執行一次
模組首次匯入發生了什麼?(以匯入boo.py
中匯入foo.py
為例)
# foo.py
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
# boo.py
import foo
print("hello world")
foo.name
foo.hello(foo.name)
foo.hello("Jack")
# 執行結果:
hello world
Hello, Hans
Hello, Jack
- 執行匯入檔案(
boo.py
)產生該檔案的全域性名稱空間 - 執行
foo.py
- 產生
foo.py
全域性名稱空間 執行foo.py
檔案內程式碼 將產生的名字全部存檔於foo.py
名稱空間 - 在匯入檔名稱空間產生一個
foo
的名字指向foo.py
全域性名稱空間
import
方法匯入模組後就可以使用模組中的所有的變數名或函式名,而且絕對不會衝突,因為呼叫的時候已經指定了要使用哪個包中的那個變數或函式
3. from...import...句式
from...import...
句式為從哪個包或模組中匯入哪個模組或功能。
示例:
# foo.py程式碼:
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
def hi():
print("Hi, world")
# boo.py程式碼:
from foo import hi #在boo中只使用foo的hi功能
print("hello world")
hi()
# 執行結果:
hello world
Hi, world
# 程式碼 boo.py
from foo import hi
from foo import hi
from foo import hi
執行結果:
from foo
# from...import...多次匯入也只會匯入一次
使用from...import...
匯入:
- 先產生執行檔案的全域性名稱空間
- 執行模組檔案 產生模組的全域性名稱空間
- 將模組中執行之後產生的名字全部存檔於模組名稱空間中
- 在執行檔案中有一個
hi
執行模組名稱空間中hi
指向的值
匯入
# foo.py 程式碼
print("from foo")
name = 'Hans'
def hello(name):
print("Hello, %s" % name)
def hi():
print("Hi, world")
# boo.py 程式碼
from foo import hi
print("hello world")
def hi():
print("from boo hi")
hi()
# 執行結果:
from foo
hello world
from boo hi # 發現執行hi()的結果為boo.py中的函式不是從foo.py中匯入進來的hi
from...import...
指定的匯入某個名字
在使用的時候直接寫名字即可 但是當前名稱空間有相同名字的時候,就會產生衝突 使用的就變成了當前名稱空間
4. 匯入方式的擴充套件
4.1 使用別名
# import匯入
>>> import foo as f # 把foo定義別名為f,這時只能呼叫f,如果再呼叫foo就會報錯,說foo沒有定義
>>> f.name
'Hans'
# from ... import ...匯入
>>> from foo import hi as h # 把hi定義為別名為h,呼叫的時候直接使用h即可,同理hi也不能使用
>>> h()
Hi, world
4.2 連續匯入
# import匯入
>>> import sys
>>> import os
# 上面的匯入方式可以寫成下面:
>>> import sys, os # 這種方式和上面的方式功能是一樣的
# from ... import ...匯入
>>> from foo import hello
>>> from foo import hi
# 上面的匯入方式可以寫成下面:
>>> from foo import hello, hi # 這種方式和上面的方式功能是一樣的
import
使用連續匯入多個模組時,如果多個模組功能相似或者屬於同一個系列時推薦使用。
如果功能不同並且不屬於一個系列 那麼推薦分行匯入
4.3 通用匯入
如果使用from ... import ...方式匯入一個模組裡全部功能時,最基本的方法是依次匯入
>>> from foo import hello, hi, name
# 或
>>> from foo import hello
>>> from foo import hi
>>> from foo import name
#可以使用* 號把一個模組裡的全部功能都匯入
>>> from foo import *
# 如果一個模組裡有三個功能,在使用from ... import ... 想讓人用其中兩個可以使用__all__
# 程式碼:
print("from foo")
name = 'Hans'
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
__all__ = ['hi', 'play'] # 在被匯入的模組檔案中可以使用__all__指定可以被匯入使用的名字
# 執行:
>>> from foo import *
from foo
>>> hi()
from foo Hi
>>> play()
from foo play
>>> hello("Hans")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'hello' is not define
4.4 判斷py檔案是作為模組檔案還是執行檔案
可以使用函式自帶的__name__
方法
# foo.py 程式碼
print("from foo")
name = 'Hans'
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
print("__name__: %s" % __name__)
# 執行如果:
from foo
__name__: __main__
# 如果foo.py是直接執行時。__name__為 __main__
# 如果foo.py 當成模組在別的檔案裡匯入時:
# importTest.py 程式碼
import foo
#執行結果:
from foo
__name__: foo
# 如果foo.py檔案是被當做模組匯入則返回模組名
#
# 一個py檔案當成模組被匯入時,它會直接執行py檔案裡的全部程式碼,可以利用__name__來判斷它是否被當成模組匯入,如果是則不執行
# 程式碼 foo.py
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
if __name__ == '__main__':
print("from foo")
name = 'Hans'
# 程式碼 importTest.py
import foo
# 執行結果:
#之前匯入的時候會直接列印: from foo
5. 模組匯入的順序
模組匯入的順序:
- 先從記憶體中查詢
- 再去內建模組中查詢
- 最後去sys.path系統路徑查詢(自定義模組)
如果都沒有查詢到則報錯
# 1.在記憶體中查詢
# foo.py 程式碼:
def hello(name):
print("from foo. Hello, %s" % name)
def hi():
print("from foo Hi")
def play():
print("from foo play")
if __name__ == '__main__':
print("from foo")
name = 'Hans'
# importTest.py 程式碼:
from foo import hello
import time
print("Hello")
time.sleep(10)
hello("time")
# 執行結果:
Hello
#在time.sleep(10)的時候把foo.py刪除,這時foo.py已經載入到記憶體中,所以下面依然執行
from foo. Hello, time
#如果再執行則會報錯
# 2.再去內建模組中查詢
# 可以自己定義一個和內建模組同名的模組,看看匯入的是誰
# 自己編寫:time.py 程式碼:
print("time...")
# boo.py 程式碼:
import time
print(time)
# 執行結果:
<module 'time' (built-in)>
# 發現time為內建的模組,所以在給py檔案命名的時候不要與內建模組名衝突
# sys.path系統路徑查詢
>>> import sys
>>> sys.path
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/local/lib64/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages/cloud_init-17.1-py3.6.egg', '/usr/lib/python3.6/site-packages', '/usr/lib64/python3.6/site-packages']
# ''為當前目錄,然後依次查詢
當某個自定義模組查詢不到的時候解決方案:
-
自己手動將該模組所在的路徑新增到sys.path中
# 檢視當前目錄 [root@hans_tencent_centos82 tmp]# pwd /tmp [root@hans_tencent_centos82 tmp]# python3 >>> import foo Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'foo' # 提示沒有foo模組。 # 查詢foo.py模組在哪 [root@hans_tencent_centos82 module]# pwd /tmp/module [root@hans_tencent_centos82 module]# ls -lrt foo.py -rw-r--r-- 1 root root 202 Nov 23 16:54 foo.py # foo.py在/tmp/module目錄下。 # /tmp/module加入到sys.path >>> import sys >>> sys.path.append('/tmp/module') >>> import foo >>> sys.path ['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/local/lib64/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages/cloud_init-17.1-py3.6.egg', '/usr/lib/python3.6/site-packages', '/usr/lib64/python3.6/site-packages', '/tmp/module'] # 可以看到 '/tmp/module'新增到sys.path
-
使用
from...import...
句式from
資料夾名稱.資料夾名稱import
模組名
from
資料夾名稱.模組名稱import
名字# from 資料夾名稱.資料夾名稱 import 模組名 # foo.py在/tmp/module目錄下。 # 當前目錄為/tmp # 使用from...import... # 執行結果: >>> from module import foo >>> foo.hi() from foo Hi #當前在/tmp下,而foo.py在/tmp/module/test/下 [root@hans_tencent_centos82 tmp]# ls -lrt /tmp/module/test/foo.py -rw-r--r-- 1 root root 202 Nov 23 16:54 /tmp/module/test/foo.py >>> from module.test import foo >>> foo.play() from foo play # from 資料夾名稱.模組名稱 import 名字 #只匯入foo模組中的一個功能: >>> from module.test.foo import play >>> play() from foo play
6. 迴圈匯入
不允許出現迴圈匯入
真要出現了,一般解決方法(就是明知道有迴圈匯入了還是讓它執行,一錯再錯方法):
- 調換順序
將彼此匯入的句式放在程式碼的最後 - 函式形式
將匯入的句式放入函式體程式碼 等待所有的名字載入完畢之後再呼叫
- 調換順序