Python 模塊
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. 循環導入
不允許出現循環導入
真要出現了,一般解決方法(就是明知道有循環導入了還是讓它運行,一錯再錯方法):
- 調換順序
將彼此導入的句式放在代碼的最後 - 函數形式
將導入的句式放入函數體代碼 等待所有的名字加載完畢之後再調用
- 調換順序