在Python中,一個.py文件就稱之為一個模塊(Module)。使用模塊還可以避免函數名和變量名衝突。為了避免模塊名衝突,Python又引入了按目錄來組織模塊的方法,稱為包(Package)。引入了包以後,模塊名字就變為「包的文件夾名.模塊的文件名」。

模塊(module)

編輯

模塊(module)可以是下述實體:

  • Python文件(.py)
  • Unix與Linux的共享對象,其後綴為.so
  • Windows的DLL,後綴為.pyd
  • 目錄,並應包含一個__init__.py文件。

任何模塊代碼的第一個字符串都被視為模塊的文檔註釋;

Python的搜索路徑sys.path,這是一個列表,包含了:

  • 當前進程的根目錄
  • PYTHONPATH 環境變量指定的路徑列表。
  • Python 標準庫目錄列表。
  • 路徑文件 (.pth) 保存的目錄 (通常放在 site-packages目錄下)

虛擬機按以下順序匹配目標模塊:

  • py 源碼文件。
  • pyc 字節碼文件。
  • egg 包文件或目錄。
  • so、dll、pyd 等擴展文件。
  • 內置模塊。
  • 其他。

Python模塊,可由import命令加載:

import module1[ as aliasname, module2[,... moduleN]

一個模塊只會被導入一次,不管執行了多少次import語句。模塊的名字追加到了當前符號表,但沒有把該模塊中的函數名稱寫入到當前符號表裏。

從模塊中導入一個指定的部分到當前命名空間中,語法如下:

from modname import name1[ as alisasname, name2[, ... nameN]]
from module2 import *

每個模塊有自己獨立的符號表,在模塊內部的函數當作全局符號表來使用。

模塊內部__xxx__這樣的變量是特殊變量,可以被直接引用,但是有特殊用途,如下列。類似_xxx和__xxx這樣的函數或變量就是非公開的(private),不應該被直接引用,即它們應視作模塊私有的名字。

  • __name__屬性,其值為模塊名 <package>.<module>;當其值是'__main__'時,表明該模塊自身在運行,否則是被引入。
  • __file__: 模塊完整⽂文件名。
  • __dict__: 模塊 globals 名字空間。
  • __doc__:模塊定義的文檔註釋

內置函數 dir() 以字符串列表的形式返回指定模塊內定義的所有名稱。

可以應對包不存在的異常:

try:
 import custommodule
except ImportError:
 pass

sys.modules 是一個字典,它包含了從 Python 開始運行起,被導入的所有模塊。鍵字就是模塊名,鍵值就是模塊對象。列出已經導入的模塊:

print('\n'.join(sys.modules.keys()))

每個 Python 類都擁有一個內置的類屬性 __module__,它定義了這個類的模塊的名字。

from math import cos
cos.__module__

卸載一個模塊:

del sys.modules["moduleName"]

可⽤用 imp.find_module() 獲取模塊的具體⽂文件信息:

imp.find_module("numpy")

import的本質

編輯

import一個模塊module_name,實質上是創建一個同名變量(module_name),其類型是module。並在sys.modules中創建一個鍵值對。該模塊中的全局代碼也會被執行。

import一個模塊時,首先查看sys.modules是否已經有了該模塊。如果有了該模塊,則無操作。

顯然,在一個模塊中import另一個模塊,也是在sys.path中搜索。

包(package)

編輯

包,是多個模塊的組織體系。目錄只有包含一個叫做 __init__.py 的文件(哪怕是空文件)才會被認作是一個包。否則,Python就把這個目錄當成普通目錄。__init__.py本身就是一個模塊,而它的模塊名就是包名。Python3中的包,__init__.py文件並不是必須的。__init__.py文件在包或內部模塊導入時自動執行,且僅執行一次。

可以有多級目錄,組成多級層次的包結構。

如果包定義文件 __init__.py 存在一個叫做 __all__ 的列表變量,那麼在使用 from package import * 的時候就把這個列表中的所有名字作為包內容導入。如果 __all__ 沒有定義,使用 from 包.子包 import * 這種語法的時候,不會導入包里的任何子模塊,只是把包和它裏面定義的所有內容導入進來。

包內部的一個模塊,可以如下引用這個包的其它模塊:

from . import another_module

import

編輯
  • 第一種用法:import module_name
  • 第二種用法:from package_name import module_name

Python會在兩個地方尋找模塊或包:sys.path、運行文件所在的目錄。python3採用絕對導入,即嵌套的import是根據最外層的運行文件的所在目錄來導入。

相對導入的辦法:

  • from . import module_name 導入和自己同目錄下的模塊
  • from .package_name import module_name 導入和自己同目錄的包的模塊。
  • from .. import module_name。導入上級目錄的模塊。
  • from ..package_name import module_name。導入位於上級目錄下的包的模塊。每多一個點就多往上一層目錄。

如果運行文件使用了相對導入,就必須進入package_name所在目錄,然後用python -m package_name.module_name來啟動執行。

其他簡單但實用的用法:

import moudle_name as alias

from module_name import function_name, variable_name, class_name。使用逗號可以導入模塊中的多個元素。

有時候導入的元素很多,可以使用反斜槓來換行,官方推薦使用括號。

from Tkinter import Tk, Frame, Button, Entry, Canvas, Text, \
    LEFT, DISABLED, NORMAL, RIDGE, END	# 反斜杠换行

from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
    LEFT, DISABLED, NORMAL, RIDGE, END)	# 括号换行(推荐)