天天看點

Python 3 | 重構

你經常會遇到這樣的情況:代碼能夠正确地運作,但可做進一步的改進——将代碼劃分為一系列完成具體工作的函數。這樣的過程被稱為重構 。重構讓代碼更清晰、更易于理 解、更容易擴充。

以下remember_me程式:

import json
# 如果以前存儲了使用者名,就加載它
# 否則,就提示使用者輸入使用者名并存儲它
filename = 'username.json'
try:
    with open(filename) as f_obj:
        username = json.load(f_obj)
except FileNotFoundError:
    username = input("What is your name? ")
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
        print("We'll remember you when you come back, " + username + "!")
else:
    print("Welcome back, " + username + "!")
           

嘗試打開檔案username.json。如果這個檔案存在,就将其中的使用者名讀取到記憶體中, 再執行else 代碼塊,即列印一條歡迎使用者回來的消息。使用者首次運作這個程式時,檔案username.json不存在,将引發FileNotFoundError 異常,是以Python将執 行except 代碼塊:提示使用者輸入其使用者名,再使用json.dump() 存儲該使用者名,并列印一句問候語。 無論執行的是except 代碼塊還是else 代碼塊,都将顯示使用者名和合适的問候語。如果這個程式是首次運作,輸出将如下:

What is your name? Zina
We'll remember you when you come back, Zina!
           

否則,輸出将如下:

Welcome back, Zina!
           

要重構remember_me.py,可将其大部分邏輯放到一個或多個函數中。remember_me.py的重點是問候使用者,是以我們将其所有代碼都放到一個名為greet_user() 的函數中:

remember.py:

import json
def greet_user():
 """問候使用者,并指出其名字"""
filename = 'username.json'
try:
    with open(filename) as f_obj:
        username = json.load(f_obj)
except FileNotFoundError:
    username = input("What is your name? ")
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
        print("We'll remember you when you come back, " + username + "!")
else:
    print("Welcome back, " + username + "!")
greet_user()
           

這個程式更清晰些,但函數greet_user() 所做的不僅僅是問候用 戶,還在存儲了使用者名時擷取它,而在沒有存儲使用者名時提示使用者輸入一個。 下面來重構greet_user() ,讓它不執行這麼多任務。為此,我們首先将擷取存儲的使用者名的代碼移到另一個函數中:

import json
def get_stored_username():
    """如果存儲了使用者名,就擷取它"""
    filename = 'username.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
            return None
    else:
        return username

def greet_user():
    """問候使用者,并指出其名字"""
    username = get_stored_username()
    if username:
        print("Welcome back, " + username + "!")
    else:
        username = input("What is your name? ")
        filename = 'username.json'
        with open(filename, 'w') as f_obj:
            json.dump(username, f_obj)
            print("We'll remember you when you come back, " + username + "!")

greet_user()
           

新增的函數get_stored_username() 目标明确,文檔字元串指出了這一點。如果存儲了使用者名,這個函數就擷取并傳回它;如果檔案username.json不存在,這個函數 就傳回None 。這是一種不錯的做法:函數要麼傳回預期的值,要麼傳回None ;這能夠使用函數的傳回值做簡單測試。

如果成功地擷取了使用者名,就打 印一條歡迎使用者回來的消息,否則就提示使用者輸入使用者名。 還需将greet_user() 中的另一個代碼塊提取出來:将沒有存儲使用者名時提示使用者輸入的代碼放在一個獨立的函數中:

import json
def get_stored_username():
    """如果存儲了使用者名,就擷取它"""
    filename = 'username.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
            return None
    else:
        return username
def get_new_username():
    """提示使用者輸入使用者名"""
    username = input("What is your name? ")
    filename = 'username.json'
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
        return username
def greet_user():
    """問候使用者,并指出其名字"""
    username = get_stored_username()
    if username:
        print("Welcome back, " + username + "!")
    else:
        username = get_new_username()
        print("We'll remember you when you come back, " + username + "!")

greet_user()
           

在remember_me.py的這個最終版本中,每個函數都執行單一而清晰的任務。

  • 調用greet_user() ,它列印一條合适的消息:要麼歡迎老使用者回來,要麼問候新使用者。
  • 它首先調用get_stored_username() ,這個函數隻負責擷取存儲的使用者名(如果存儲了的話)。
  • 再在必要時調用get_new_username() ,這個函數隻負責擷取并存儲新使用者的使用者名。

要編寫出清晰而易于維護和擴充的代碼,這種劃分工作必不可少。