Try   HackMD

程式碼模組化與應用

讓程式碼更容易被維護、除錯的方法

模組化可以想成許多的積木,可以快速被取用、組合成各種物品。

隨著程式碼越來越龐大複雜,設計程式時也應該遵循這樣的設計原則,包括:

  • 執行程序模組化:使用函式(Function)
  • 資料格式模組化:使用物件(Object)類別(Class)
  • 系統檔案模組化:使用函式庫(Library)套件(Package)模組(Module)應用程式介面(API)

以上設計原則,都是為了程式可以更容易被維護、除錯。

執行程序模組化:函式(Function)

在Python中,我們使用函式(Function)將重複出現的程式碼,通常是一系列的程序,做成函式,可以隨時呼叫使用,增加開發效率、以及讓程式碼更容易維護。

主要好處如下:

  • 減少撰寫重覆的程式碼
  • 將程式碼以有意義的方式組織起來
  • 相同的流程下,可藉由參數調整程式的行為
  • 藉由函式庫可組織和分享程式碼
  • 做為資料結構 (data structures) 和物件 (objects) 的基礎

函式的宣告

函式包含以下部分:

  • 函式的名稱 (identifier)
  • 函式的參數 (parameters),相當於輸入
  • 函式的回傳值 (return value),相當於輸出
  • 函式的本體 (body)

函式的類型

函式分成兩種類型,有回傳值無回傳值
請參考以下範例程式碼:

# 無回傳值 def function1(): print("Hello") # 有回傳值 def function2(): a = 0 a += 1 return a #呼叫function 1 function1() #呼叫function 2 print(function2())

函式的參數

函式可以帶入參數,在函式內使用該參數進行運算,但也可以不帶入參數。

# 無帶入參數 def function1(): a = 0 b = 0 a += 1 b = a return b # 有帶入參數 def function2(a): b = 0 a += 1 b = a return b # 呼叫function 1 print(function1()) # 呼叫function 2 x = 2 print(function2(x))

變數範圍(Variable Scope)

在函式裡宣告使用的變數,與函式外的變數,有不同的使用範圍限制,我們稱為Variable Scope

分成兩種:

  • 廣域範圍(global scope)
    或稱module scope,範圍是單個檔案(*.py)。
    模組(或app)是層層堆疊起來的,並不會說哪裡才是真正的global環境,要說的話,最接近的可能就是built-in的變數如True、None所宣告的地方吧
  • 區域範圍(local scope)
    以函式function為範圍,scope伴隨函式被呼叫時建立,變數重新綁定

可以透過函式globals()locals()輸出該scope的所有變數

函式進階使用技巧:遞迴

遞迴(Recursion),定義如下。

一個函式,由自身定義或呼叫,且具備以下兩個條件,就叫做遞迴。
1. 可以反覆執行的過程
2. 跳出執行過程的出口

根據呼叫對象不同,遞迴可分成兩種

  1. 直接遞迴:Function自身呼叫自己。
def Func(...): ... if(...) Func(...) ...
  1. 間接遞迴:Function之間互相呼叫。
def Func1(): ... if(...) Func2() ... def Func2(): ... if(...) Func1() ...

隨堂練習

  1. 階乘的計算

階乘的基本定義如下

  • n == 0, n! = 1
  • n > 0, n! = n x (n-1)!, n正整數

請利用遞迴的技巧設計程式,計算 4! 為何?

參考程式碼如下:

def factorial(n): if n == 0: return 1 else: return( n * factorial(n-1)) print(factorial(4))
  1. 請設計程式,請使用者輸入身高(cm)與體重(kg),並且設計兩個版本的函式來計算BMI值,名稱叫做bmi_calculator
  • 版本1. 有參數(身高與體重)、有回傳值(bmi值)
  • 版本2. 無參數、無回傳值

Note: BMI計算公式:BMI=(體重/身高^2)

參考程式碼:
版本1. 有參數(身高與體重)、有回傳值(bmi值)

def bmi_calculator(height, weight): bmi = weight/(height/100)**2 return bmi user_height = int(input("請輸入身高(cm)> ")) user_weight = int(input("請輸入體重(kg)> ")) bmi_result = bmi_calculator(user_height, user_weight) print("你的BMI是 {0:.2f}".format(bmi_result))

版本2. 無參數、無回傳值

def bmi_calculator(): user_height = int(input("請輸入身高(cm)> ")) user_weight = int(input("請輸入體重(kg)> ")) print("你的BMI是 {0:.2f}".format(bmi_result)) bmi_calculator()

資料格式模組化:物件與類別

由於物件與類別的應用,較適合大型程式應用,例如遊戲、大型網站,在此不特別介紹,若有興趣,請參考補充資料:物件與類別

系統檔案模組化:函式庫、套件、模組、API

  1. 模組(Module):一個.py檔案就是一個 module,裡頭可以定義 variable, function, class
  2. 套件(Package):一個檔案資料夾,裡面存放多個module (.py檔案)
  3. 函式庫(Library):根據特定用途,將多個Package集合在一個資料夾中
  4. 應用程式介面(API, Application Programming Interface):Library開發者可定義哪些module中的function可以給別人引用,這些function就稱為API。對於API引用者,不需要了解實作內容,只需要說明文件知道API用途,自行使用開發新程式。

函式庫引用範例:使用第三方函式庫openpyxl

我們再回頭看這個使用第三方函式庫openpyxl的範例

import openpyxl import os # os.chdir 是 python 切換到電腦指定路徑的方法 os.chdir(r"/Users/chaoyen/Downloads") # 請填寫自己電腦裡Excel檔案的絕對路徑 wb = openpyxl.load_workbook('produceSales.xlsx') # 請填寫要處理的Excel檔案名稱 sheet = wb.worksheets[0] # 要更正的品名與其單價 price_updates_dict = {'Garlic': 1.99} #使用for loop掃描所有A欄品名,如果比對一致,就進行更正與上色 print("Processing...") for rowNum in range(2, sheet.max_row, 1): produceName = sheet.cell(rowNum, 1).value if produceName in price_updates_dict: sheet.cell(rowNum, 2).value = price_updates_dict[produceName] # openpyxl函式庫中的styles模組的Font API sheet.cell(rowNum, 2).font = openpyxl.styles.Font(color='FF0000') # 將結果另存新檔 wb.save('produceSales_update.xlsx') print("Done!")

小提示:如果第19行想直接引用Font,可以在第三行新增這行程式碼

from openpyxl.styles import Font

硬體應用API實務:Moxa UC-8100 API Library

以下內容節錄自Moxa UC-8100的User Manual,跟購買者說明,如何引用Moxa定義的API,來開發程式,控制UC-8100這台IoT Gateway

有經驗的開發者看到這份手冊,就可以知道Moxa的API主要是以C語言撰寫的,在呼叫API前,要安裝相關套件。

軟體應用API實務: Google Map API Library

以下內容節錄自Google Maps Platform,這裡提供給想要使用Google Map API來做應用的開發者

有經驗的開發者看到這個網站的說明,就可以知道Google Map的API主要是以Javascript撰寫的。

隨堂練習

請設計大樂透的報明牌程式,從1~49裡面,隨機抽出六個不重複的數字
請引用random.sample這個模組來隨機取出六個數字

不直接引用sample API

import random num = 49 num_list = [] for i in range(0, num, 1): num_list.append(i+1) # random.sample print(f'Your lucky number: {random.sample(num_list, 6)}')

直接引用sample API

from random import sample num = 49 num_list = [] for i in range(0, num, 1): num_list.append(i+1) print(f'Your lucky number: {sample(num_list, 6)}')
tags: Python程式設計入門