Jupyter Notebook 不僅支援 Python,也支援其他程式語言,適合跨語言環境的原型開發。透過建立獨立的邏輯區塊(儲存格),開發者可以逐步執行程式碼並觀察結果,同時保有變數內容,提升開發效率。本文將引導讀者設定 Jupyter 開發環境,並示範如何使用 psutil 函式庫取得系統資訊,最後將 Jupyter Notebook 轉換為可執行的 Python 指令碼,建立簡潔易用的命令列介面。此流程能有效地將原型設計轉化為正式的程式碼,方便後續開發與維護。
支援多語言的 Jupyter 與原型開發環境
Jupyter 的設計目標之一是支援多種程式語言,這意味著它不僅支援 Python,還支援 Haskell、Lua、Perl、PHP、Rust、Node.js 等多種語言。每種語言都有其對應的 IDE、REPL、檔案網站等。使用 Jupyter 進行原型開發的一大優勢在於,它允許開發者建立一個跨不同環境和語言的工作流程。例如,全端網頁程式設計師經常需要在 Python 和 JavaScript 之間切換,而科學家可能需要在 Python 和 R 之間切換。單一介面使得不同語言之間的差異得以平滑過渡。
安裝 Jupyter
由於 Jupyter 不是專為 Python 設計,並且內建支援選擇後端來執行目前的程式碼,建議以方便的方式在整個系統中安裝它。如果通常將 Python 工具安裝在虛擬環境中,這樣做是可以的。然而,玄貓建議將 Jupyter 安裝在使用者環境中:
python -m pip install –user jupyter
內容解密:
python -m pip:使用 Python 的套件管理器 pip。install --user jupyter:將 Jupyter 安裝在使用者環境中,而不是全域環境。
安裝完成後,需確保二進位制檔案目錄已包含在系統路徑中。或者,可以選擇將 Jupyter 安裝在全域 Python 環境中,或透過套件管理器安裝。保持工具安裝的一致性比使用多種方法更為重要。
使用 Jupyter 進行原型開發
在 Jupyter 中,可以將程式碼分成邏輯區塊,並可個別或順序執行。這些區塊是可編輯且持久的,就像使用指令碼一樣,但可以控制哪些區塊執行,並在不丟棄變數內容的情況下寫入新程式碼。這與使用 REPL 的方式類別似,可以在不中斷程式流程的情況下進行嘗試。
Jupyter 有兩種主要的使用方式:透過網頁使用 Jupyter 的筆記本伺服器,或作為標準 Python REPL 的替代品。兩者都根據相同的底層介面 IPython。IPython 不會像標準 REPL 那樣在縮排方面出現問題,並且支援輕鬆重新執行之前程式碼。
筆記本介面
要開始進行原型開發,請啟動 Jupyter 筆記本伺服器,然後透過網頁介面建立新的筆記本。
jupyter notebook
載入筆記本後,將程式碼輸入第一個儲存格,然後點選執行按鈕。許多常見於程式碼編輯器的鍵盤快捷鍵都可以在這裡使用,同時還具備自動縮排功能。
內容解密:
jupyter notebook:啟動 Jupyter 筆記本伺服器。- 自動縮排功能:在輸入程式碼時,Jupyter 會自動進行縮排,使程式碼更易讀。
除錯功能
Jupyter 筆記本支援 pdb 除錯工具,可以中斷執行並顯示新的輸入提示,就像在命令列中一樣。所有標準的 pdb 功能都可透過此介面使用,因此本章中關於 pdb 的技巧同樣適用於 Jupyter 環境。
各種原型開發方法的比較
本章探討了多種原型開發方法,每種方法都有其優缺點,適用於不同的場景。對於簡單的一行程式碼,例如列表推導式,使用 REPL 是最快的選擇。而對於更複雜的任務,例如結合外部函式庫的函式,使用功能更豐富的方法通常更有效率。
下表比較了不同原型開發環境的功能:
| 功能 | REPL | 指令碼 | 指令碼 + pdb | Jupyter | Jupyter + pdb |
|---|---|---|---|---|---|
| 縮排規則 | 嚴格 | 正常 | 正常 | 正常 | 正常 |
| 重複執行 | 單行 | 整個指令碼 | 整個指令碼或跳到前一行 | 邏輯區塊 | 邏輯區塊或逐行 |
| 持續性 | 無儲存 | 命令儲存 | 命令儲存,但 pdb 互動不儲存 | 命令和輸出儲存 | 命令和輸出儲存 |
內容解密:
- REPL:適合簡單、快速測試的環境。
- 指令碼:適合較複雜、需要完整執行的任務。
- Jupyter:適合需要互動式開發和逐步除錯的場景。
使用Jupyter Notebook進行原型開發與環境設定
在進行Python專案開發時,選擇適合的開發工具和環境至關重要。本章將探討使用Jupyter Notebook進行原型開發的優勢,以及如何設定和管理專案環境。
選擇Jupyter Notebook的原因
由於我們的專案涉及多個不同的資料來源,並且需要能夠重複執行之前的命令,因此Jupyter Notebook成為了一個理想的選擇。相較於REPL和指令碼式開發,Jupyter Notebook提供了更好的互動性和靈活性。
比較不同的開發方法
| 功能 | REPL | 指令碼 | 指令碼 + pdb | Jupyter | Jupyter + pdb |
|---|---|---|---|---|---|
| 縮排程式碼 | ✔ | ✔ | ✔ | ✔ | ✔ |
| 重複執行之前的命令 | ❌ | ⚠ | ⚠ | ✔ | ✔ |
| 逐步除錯 | ❌ | ❌ | ⚠ | ✔ | ⚠ |
| 自省能力 | ✔ | ✔ | ✔ | ✔ | ✔ |
| 永續性 | ❌ | ✔ | ✔ | ✔ | ✔ |
| 編輯能力 | ❌ | ✔ | ✔ | ✔ | ✔ |
環境設定
為了管理專案的依賴關係,我們需要建立一個虛擬環境。這裡我們使用pipenv工具來建立和管理虛擬環境。
為什麼選擇Pipenv?
Python有多種建立虛擬環境的工具,如virtualenv、venv、conda等。pipenv因其優秀的依賴管理功能而被選用。它能夠確保專案的依賴關係被正確管理,並且保持環境的更新。
> python -m pip install --user pipenv
建立新專案
首先,建立一個新的專案目錄,並切換到該目錄下。然後,使用pipenv安裝ipykernel作為開發依賴。
> mkdir advancedpython
> cd advancedpython
> pipenv install ipykernel --dev
> pipenv run ipython kernel install --user --name=advancedpython
啟動Jupyter Notebook
安裝完成後,可以啟動Jupyter Notebook,並在新的命令視窗中執行。
> cd advancedpython
> jupyter notebook
詳細步驟解析
安裝Pipenv
> python -m pip install --user pipenv
內容解密:
python -m pip:使用Python的包管理器pip。install --user pipenv:安裝pipenv工具,並將其安裝在使用者目錄下,避免需要管理員許可權。
建立專案與安裝依賴
> mkdir advancedpython
> cd advancedpython
> pipenv install ipykernel --dev
內容解密:
mkdir advancedpython:建立一個名為advancedpython的新目錄。cd advancedpython:切換到新建立的目錄。pipenv install ipykernel --dev:使用pipenv安裝ipykernel,並將其標記為開發依賴。
組態IPython Kernel
> pipenv run ipython kernel install --user --name=advancedpython
內容解密:
pipenv run:在pipenv管理的虛擬環境中執行命令。ipython kernel install:安裝IPython kernel。--user --name=advancedpython:將kernel安裝在使用者目錄下,並命名為advancedpython。
啟動Jupyter Notebook
> jupyter notebook
內容解密:
jupyter notebook:啟動Jupyter Notebook服務,允許使用者透過網頁介面進行互動式開發。
在 Jupyter 環境中進行原型設計與環境設定
當我們在新的 pipenv 目錄中開啟 Jupyter 時,自動開啟的網頁瀏覽器會顯示 Jupyter 的介面,並列出我們所建立的目錄內容,如圖 1-3 所示。接下來,我們需要建立一個新的 notebook 來開始我們的原型設計。選擇 “New” 然後選擇 “advancedpython” 來建立一個新的 notebook。
Jupyter Notebook 的基本操作
在 Jupyter 的主要編輯介面中,我們可以看到一個空白的「儲存格」(cell),我們可以在其中輸入程式碼並透過點選 “Run” 按鈕來執行。Jupyter 會在儲存格下方顯示執行的結果,並自動建立一個新的空白儲存格供進一步使用。可以把儲存格視為一個函式體,通常包含多個相關的陳述句,這些陳述句會被視為一個邏輯群組來執行。
原型設計:取得系統資訊
首先,我們會建立一個 Python 程式來傳回它所執行的系統的各種資訊。這些資訊將成為之後資料彙總的一部分,但目前我們先從簡單的資料開始。
步驟 1:取得 Python 版本資訊
首先,我們在第一個儲存格中輸入以下程式碼來取得 Python 的版本資訊,如圖 1-4 所示。
import sys
sys.version_info
Jupyter 會顯示儲存格最後一行的值,以及任何明確的輸出結果。在這個例子中,由於 sys.version_info 是最後一行,所以它的值會被顯示出來。
內容解密:
import sys:匯入 Python 的標準函式庫sys,該函式庫提供了許多與 Python 直譯器及其環境相關的功能。sys.version_info:取得目前 Python 直譯器的版本資訊。
繼續原型設計:取得 IP 地址
接下來,我們要取得目前機器的 IP 地址。這需要進行一些 API 呼叫和資訊處理,因此我們會逐步在新的儲存格中建立變數,以方便觀察每一步的結果。
步驟 2:逐步取得 IP 地址
我們將透過多個儲存格逐步完成這個任務。最終,我們會得到類別似圖 1-5 的結果,顯示與目前電腦相關的各種 IP 地址。
合併儲存格
當我們完成了 IP 地址的取得後,會發現有三個儲存格。為了整理,我們可以選取最上方的儲存格,然後從編輯選單中選擇 “Merge Cell Below” 兩次,將這三個儲存格合併成一個,如圖 1-6 所示。
安裝相依套件:psutil
為了取得系統的負載資訊,我們需要安裝 psutil 這個相依套件。在終端機中執行以下指令:
pipenv install psutil
安裝完成後,我們需要重新啟動 Jupyter 的 kernel,以確保新的相依套件可供使用。
探索 psutil 模組
重新啟動 kernel 後,我們可以在 notebook 中匯入 psutil 並開始探索其功能。
import psutil
psutil.cpu_stats()
內容解密:
import psutil:匯入psutil模組,該模組提供了許多用於取得系統資訊的功能。psutil.cpu_stats():取得 CPU 的統計資訊。
使用 Jupyter 進行原型開發與環境設定
探索 psutil 函式庫
在 Jupyter Notebook 中,我們可以使用 psutil 函式庫來取得系統資源使用情況。首先,我們匯入 psutil 並使用 cpu_stats 函式來取得 CPU 使用情況。然而,這個函式提供的資訊較為晦澀,不易理解。因此,我們改用 cpu_percent 函式來取得 CPU 使用率。
使用 cpu_percent 函式
cpu_percent 函式需要一個可選的 interval 引數,用於指定函式執行時間。如果 interval 為非零值,函式會在指定時間後傳回 CPU 使用率。我們將 interval 設定為 0.1 秒,以取得準確的資料。
import psutil
psutil.cpu_percent(interval=0.1)
練習 1-1:探索函式庫
我們可以利用 Jupyter 的自動完成和幫助功能來探索 psutil 函式庫的其他函式。每個有趣的函式都值得建立一個新的儲存格來測試。由於不同的作業系統支援的函式不同,因此在 Windows 上可用的函式可能會較少。
將匯入陳述式移到頂部儲存格
為了避免在每個儲存格中重複匯入 psutil,我們將匯入陳述式移到新的頂部儲存格中。這樣可以使程式碼更易於維護,也符合 Python 模組的慣例。
執行儲存格
在 Jupyter Notebook 中,每個儲存格都可以獨立執行。儲存格左側的數字表示執行的順序。我們可以利用「儲存格」選單中的「全部執行」功能來執行所有儲存格,就像執行一個標準的 Python 指令碼一樣。
修改 cpu_percent 函式的使用
為了示範 Jupyter 的靈活性,我們將 cpu_percent 函式的 interval 設定為 5 秒。這樣可以讓我們觀察到 Jupyter 如何允許我們編寫耗時的設定程式碼,同時仍然可以重新執行較快的部分,而無需等待慢速的部分。
import psutil
psutil.cpu_percent(interval=5)
將 Jupyter Notebook 匯出為 Python 指令碼
雖然 Jupyter 是原型開發的良好工具,但它並不適合作為專案的主要開發環境。我們可以使用 Jupyter 的 nbconvert 子命令將 Notebook 匯出為 Python 指令碼。
jupyter nbconvert --to script Untitled.ipynb
匯出的 Python 指令碼(例如 Untitled.py)包含了原始 Notebook 中的所有程式碼,每個儲存格之間以註解分隔。
將匯出的指令碼轉換為可用的 Python 指令碼
我們可以將匯出的指令碼轉換為可用的 Python 指令碼,方法是將匯入陳述式移到檔案頂部,並將每個儲存格轉換為一個名為函式。同時,我們需要修改程式碼以傳回結果,而不是直接列印或輸出。
serverstatus.py
# coding: utf-8
import sys
import socket
import psutil
def python_version():
return sys.version_info
def ip_addresses():
hostname = socket.gethostname()
addresses = socket.getaddrinfo(hostname, None)
address_info = []
for address in addresses:
address_info.append((address[0].name, address[4][0]))
return address_info
def cpu_load():
return psutil.cpu_percent()
def ram_available():
return psutil.virtual_memory().available
def ac_connected():
return psutil.sensors_battery().power_plugged
建立命令列介面
為了讓這些函式更有用,我們可以建立一個簡單的命令列應用程式來顯示這些資料。我們使用了一個稱為「ifmain」的慣用語法來實作這一點。
def do_something():
print("Do something")
if __name__ == '__main__':
do_something()
內容解密:
if __name__ == '__main__'::這是一個特殊的 Python 語法,用於判斷目前指令碼是否為主程式。如果是,則執行do_something()函式。do_something():這是一個範例函式,用於示範如何建立一個簡單的命令列應用程式。- 命令列介面:透過使用
if __name__ == '__main__':語法,我們可以建立一個簡單的命令列應用程式,讓使用者可以輕鬆地執行我們的程式碼。
結合 serverstatus.py 的完整範例:
# coding: utf-8
import sys
import socket
import psutil
def python_version():
return sys.version_info
def ip_addresses():
hostname = socket.gethostname()
addresses = socket.getaddrinfo(hostname, None)
address_info = []
for address in addresses:
address_info.append((address[0].name, address[4][0]))
return address_info
def cpu_load():
return psutil.cpu_percent(interval=0.1)
def ram_available():
return psutil.virtual_memory().available
def ac_connected():
return psutil.sensors_battery().power_plugged
if __name__ == '__main__':
print("Python 版本:", python_version())
print("IP 位址:", ip_addresses())
print("CPU 負載:", cpu_load())
print("可用 RAM:", ram_available())
print("AC 電源連線:", ac_connected())
內容解密:
python_version():傳回目前 Python 的版本資訊。ip_addresses():傳回目前主機的 IP 位址資訊。cpu_load():傳回目前 CPU 的負載情況。ram_available():傳回目前可用的 RAM 容量。ac_connected():傳回目前是否連線 AC 電源。if __name__ == '__main__'::判斷目前指令碼是否為主程式,如果是,則列印出上述資訊。