翻譯:《實用的Python編程》03_04_Modules
目錄 | 上一節 (3.3 錯誤檢查) | 下一節 (3.5 主模塊)
3.4 模塊
本節介紹模塊的概念以及如何使用跨多個文件的函數。
模塊和導入
任何一個 Python 源文件都是一個模塊。
# foo.py
def grok(a):
...
def spam(b):
...
import 語句加載并執行一個模塊。
# program.py
import foo
a = foo.grok(2)
b = foo.spam('Hello')
...
命名空間
模塊是命名值的集合,有時也稱為命名空間。名稱是源文件中定義的所有全局變量和函數。導入之后,模塊名稱用作前綴。因此,稱為命名空間。
import foo
a = foo.grok(2)
b = foo.spam('Hello')
...
模塊名直接綁定到文件名(foo -> foo.py)。
全局定義
填充模塊命名空間的內容是定義在全局(global)作用域中任何內容。考慮定義了相同變量 x 的兩個模塊。
# foo.py
x = 42
def grok(a):
...
# bar.py
x = 37
def spam(a):
...
在本例中,x 指向不同的變量。一個是 foo.x,另一個是 bar.x。不同的模塊可以使用相同的名稱并且這些名稱不會相互沖突。
模塊是隔離的。
把模塊當做環境
對于所有定義在模塊里面的代碼而言,模塊構成一個封閉的環境。
# foo.py
x = 42
def grok(a):
print(x)
全局變量始終綁定到封閉模塊(相同文件),每個源文件都是它自己的小宇宙。
模塊執行
導入模塊時,模塊中的所有語句依次執行(execute),直到到達文件末尾。模塊命名空間的內容是所有的全局名稱,這些名稱在執行過程結束時仍然被定義。如果有腳本語句在全局作用域中執行任務(如打印,創建文件等),您將看到它們在導入模塊時運行。
import as 語句
可以在導入模塊時更改其名稱:
import math as m
def rectangular(r, theta):
x = r * m.cos(theta)
y = r * m.sin(theta)
return x, y
它的作用與普通導入相同,僅僅是重命名模塊而已。
from import語句
from import語句從模塊中選出符號并使它們在局部可訪問。
from math import sin, cos
def rectangular(r, theta):
x = r * cos(theta)
y = r * sin(theta)
return x, y
這允許使用模塊的某些部分,而不必輸入模塊前綴。對于經常使用的名稱,這非常有用。
導入說明
有關導入的各種變化不改變模塊的工作方式。
import math
# vs
import math as m
# vs
from math import cos, sin
...
具體來說,import 始終執行整個文件并且模塊仍然是隔離的環境。
import module as 語句只局部地更改名稱。在后臺,from math import cos, sin 語句仍加載全部的數學模塊。當導入完成后,它僅僅將模塊中的 cos 和 sin 名稱復制到局部命名空間中。
模塊加載
每個模塊僅加載和執行一次。注意:重復導入僅返回先前所加載模塊的引用
sys.modules 是所有已加載模塊的字典。
>>> import sys
>>> sys.modules.keys()
['copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath', ...]
>>>
注意:當修改模塊的源代碼后,如果重復import語句會產生一個常見的困惑。由于模塊緩存 sys.modules,重復導入總是返回之前加載的模塊——即使更改已經發生。將修改后的代碼加載到 Python 中最安全的方式是退出然后重啟解釋器。
定位模塊
搜索模塊時,Python 從路徑列表(sys.path)中查詢。
>>> import sys
>>> sys.path
[
'',
'/usr/local/lib/python36/python36.zip',
'/usr/local/lib/python36',
...
]
當前工作目錄通常是第一個。
模塊搜索路徑
如前所述,sys.path 包含搜索路徑。可以根據需要手動調整 。
import sys
sys.path.append('/project/foo/pyfiles')
也可以通過環境變量添加搜索路徑。
% env PYTHONPATH=/project/foo/pyfiles python3
Python 3.6.0 (default, Feb 3 2017, 05:53:21)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
>>> import sys
>>> sys.path
['','/project/foo/pyfiles', ...]
在大部分情況下,沒必要手動調整模塊搜索路徑。但是,如果嘗試導入的 Python 代碼位于特殊位置,或者無法從當前工作目錄輕松訪問,那么就需要手動調整搜索路徑了。
練習
因為本練習涉及模塊,所以確保在適當的環境中運行 Python 至關重要。模塊經常給編程新手帶來問題,這些問題與當前工作目錄相關或者與 Python 路徑設置相關。對于本課程,假定您是在 Work/ 目錄下編寫所有的代碼。為了獲得最佳結果,應該確保也是在 Work/ 目錄下運行解釋器。否則,需要確保 practical-python/Work 已添加到 sys.path。
練習 3.11:模塊導入
在第 3 節中,我們創建了一個通用目標函數 parse_csv() 用于解析 CSV 數據文件的內容。
現在,我們來看看如何在其它程序中使用該函數。首先,啟動一個新的 shell 窗口,進入到放置所有文件的目錄中。我們將要導入它們。
啟動 Python 交互模式。
bash % python3
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
當Python 交互模式啟動后,嘗試導入某些之前編寫的程序。應該能看到輸出和以前一樣。強調一下,導入模塊會運行模塊中的代碼。
>>> import bounce
... watch output ...
>>> import mortgage
... watch output ...
>>> import report
... watch output ...
>>>
如果沒有代碼運行,可能是因為在錯誤的目錄下運行了 Python。現在,嘗試導入 fileparse 模塊并獲取有關該模塊的幫助。
>>> import fileparse
>>> help(fileparse)
... look at the output ...
>>> dir(fileparse)
... look at the output ...
>>>
嘗試使用 fileparse 模塊來讀取一些數據:
>>> portfolio = fileparse.parse_csv('Data/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... look at the output ...
>>> pricelist = fileparse.parse_csv('Data/prices.csv',types=[str,float], has_headers=False)
>>> pricelist
... look at the output ...
>>> prices = dict(pricelist)
>>> prices
... look at the output ...
>>> prices['IBM']
106.11
>>>
嘗試導入一個函數,以便不用再包含模塊名:
>>> from fileparse import parse_csv
>>> portfolio = parse_csv('Data/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... look at the output ...
>>>
練習 3.12:使用庫模塊
在第 2 節中,編寫了 report.py 程序用來生成像下面這樣的股票報告:
Name Shares Price Change
---------- ---------- ---------- ----------
AA 100 9.22 -22.98
IBM 50 106.28 15.18
CAT 150 35.46 -47.98
MSFT 200 20.89 -30.34
GE 95 13.48 -26.89
MSFT 50 20.89 -44.21
IBM 100 106.28 35.84
使用該程序并對其進行修改,以便使用 fileparse 模塊中的函數完成所有輸入文件的處理。為此,將 fileparse 作為模塊導入,并修改 read_portfolio() 和 read_prices() 函數以便使用 parse_csv() 函數。
在本練習開始時,請使用交互示例作為指南。之后,應該能夠獲得與之前完全相同的輸出。
練習 3.14:使用更多的庫導入
在第 1 節中,編寫了一個讀取股票投資組合和計算費用的程序 pcost.py。
>>> import pcost
>>> pcost.portfolio_cost('Data/portfolio.csv')
44671.15
>>>
請修改 pcost.py 文件,以便它能夠使用 report.read_portfolio() 函數。
說明
當完成練習后,您應該擁有三個程序。包含通用目的函數 parse_csv() 的fileparse.py 程序。用于生成報告,且包含 read_portfolio() 和 read_prices() 函數的 report.py 程序。最后,利用 report.py 程序中編寫的read_portfolio() 函數去計算股票投資組合費用的 pcost.py 程序。
浙公網安備 33010602011771號