翻譯:《實用的Python編程》03_01_Script

目錄 | 上一節 (2.7 對象模型) | 下一節 (3.2 深刻函數)python

3.1 腳本

在該部分,咱們將深刻研究編寫 Python 腳本的慣例。git

什麼是腳本?

腳本就是運行和終止一系列語句的程序。github

# program.py

statement1
statement2
statement3
...

到目前爲止,咱們主要在編寫腳本。segmentfault

問題

若是你編寫一個有用的腳本,它的特性和功能將會增長。你可能想要將其應用於相關的問題。隨着時間的推移,它可能會成爲一個關鍵的應用程序。若是你不注意的話,它可能會變成一團亂麻。所以,讓咱們有條理的組織程序吧。app

定義變量

名稱必須在使用以前定義。模塊化

def square(x):
    return x*x

a = 42
b = a + 2     # Requires that `a` is defined

z = square(b) # Requires `square` and `b` to be defined

順序很重要。函數

幾乎老是把變量和函數的定義放到頂部附近。工具

定義函數

把全部與單個任務相關的代碼都放到一個地方是個好主意。能夠使用函數實現:開發工具

def read_prices(filename):
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

函數也能夠簡化重複的操做。ui

oldprices = read_prices('oldprices.csv')
newprices = read_prices('newprices.csv')

什麼是函數?

函數是命名的語句序列。

def funcname(args):
  statement
  statement
  ...
  return result

任何 Python 語句均可以在函數內部使用。

def foo():
    import math
    print(math.sqrt(2))
    help(math)

Python 中沒有特殊語句(這使它很容易記住)。

函數定義

能夠按任何順序定義函數。

def foo(x):
    bar(x)

def bar(x):
    statements

# OR
def bar(x):
    statements

def foo(x):
    bar(x)

在程序執行期間,函數必須在實際使用以前(調用)定義。

foo(3)        # foo must be defined already

在文體上,函數以自底向上的方式定義可能更常見。

自底向上的風格

函數被當作構建塊。較小/較簡單的塊優先。

# myprogram.py
def foo(x):
    ...

def bar(x):
    ...
    foo(x)          # Defined above
    ...

def spam(x):
    ...
    bar(x)          # Defined above
    ...

spam(42)            # Code that uses the functions appears at the end

後面的函數基於前面的函數構建。再次說明,這僅僅是一種風格問題。在上面程序中惟一重要的事情是 spam(42) 的調用是在最後一步。

函數設計

理想狀況下,函數應該是一個黑盒。它們應該僅對輸入進行操做,並避免全局變量和奇怪的反作用。首要目標:模塊化和可預測性。

文檔字符串

以文檔字符串(doc-string)的形式包含文檔是良好的實踐。文檔字符串是緊接着函數名的字符串。它們用於 help() 函數,集成開發環境和其它的工具。

def read_prices(filename):
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

一個好的文檔字符串實踐是寫一句簡短的話總結該函數作什麼。若是須要更多的信息,請包含一個簡短的帶有更詳細的參數說明的使用示例,

類型註解

也能夠添加可選的類型提示到函數定義中。

def read_prices(filename: str) -> dict:
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

提示在操做上什麼也不作。它們純粹是信息性的。可是,集成開發工具,代碼檢查器,以及其它工具可能會使用它來執行更多的操做。

練習

在第 2 節中,編寫了一個名爲 report.py 的程序,該程序能夠打印出顯示股票投資組合績效的報告。此程序包含一些函數。例如:

# report.py
import csv

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    portfolio = []
    with open(filename) as f:
        rows = csv.reader(f)
        headers = next(rows)

        for row in rows:
            record = dict(zip(headers, row))
            stock = {
                'name' : record['name'],
                'shares' : int(record['shares']),
                'price' : float(record['price'])
            }
            portfolio.append(stock)
    return portfolio
...

可是,程序的有些部分僅執行一系列的腳本計算。這些代碼出如今程序結尾處。例如:

...

# Output the report

headers = ('Name', 'Shares', 'Price', 'Change')
print('%10s %10s %10s %10s'  % headers)
print(('-' * 10 + ' ') * len(headers))
for row in report:
    print('%10s %10d %10.2f %10.2f' % row)
...

在本練習中,咱們使用函數來對該程序進行有條理的組織,使程序更健壯。

練習 3.1:將程序構造爲函數的集合

請修改 report.py 程序,以便全部主要操做(包括計算和輸出)都由一組函數執行。特別地:

  • 建立打印報告的函數 print_report(report)
  • 修改程序的最後一部分,使其僅是一系列函數調用,而無需進行其它運算。

練習 3.2:爲程序執行建立一個頂層函數

把程序的最後一部分打包到單個函數 portfolio_report(portfolio_filename, prices_filename) 中。讓程序運行,以便下面的函數調用像以前同樣建立報告。

portfolio_report('Data/portfolio.csv', 'Data/prices.csv')

在最終版本中,程序只不過是一系列函數定義,最後是對單個函數portfolio_report() 的調用(它執行程序中涉及的全部步驟)。

經過將程序轉換爲單個函數,在不一樣的輸入後能夠很輕鬆地運行它。例如,在運行程序後以交互方式嘗試這些語句:

>>> portfolio_report('Data/portfolio2.csv', 'Data/prices.csv')
... look at the output ...
>>> files = ['Data/portfolio.csv', 'Data/portfolio2.csv']
>>> for name in files:
        print(f'{name:-^43s}')
        portfolio_report(name, 'Data/prices.csv')
        print()

... look at the output ...
>>>

說明

Python 使在有一系列語句的文件中編寫相對無結構的腳本變得很輕鬆。整體來講,不管什麼時候,儘量地利用函數一般老是更好的選擇。在某些時候,腳本會不斷增長,而且咱們但願它更有組織。另外,一個不爲人知的事實是,若是使用函數,Python 的運行會更快一些。

目錄 | 上一節 (2.7 對象模型) | 下一節 (3.2 深刻函數)

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

相關文章
相關標籤/搜索