翻譯:《實用的Python程式設計》03_04_Modules

codists 發表於 2021-03-03

目錄 | 上一節 (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 語句仍載入全部的數學模組。當匯入完成後,它僅僅將模組中的 cossin 名稱複製到區域性名稱空間中。

模組載入

每個模組僅載入和執行一次。注意:重複匯入僅返回先前所載入模組的引用

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 程式。

目錄 | 上一節 (3.3 錯誤檢查) | 下一節 (3.5 主模組)

注:完整翻譯見 https://github.com/codists/practical-python-zh