Skip to main content

7 posts tagged with "Python"

View All Tags

· 12 min read
Willis Chen

為什麼該用 uv 取代傳統的 Python venv?

你有沒有遇過這種狀況:寫 Python 程式時,明明在自己電腦能跑,但換到同學的電腦就出錯?或者安裝了一個新套件後,之前的程式竟然跑不動了?

這就像你在房間裡亂丟衣服,最後找不到想穿的衣服一樣!今天要介紹一個超厲害的工具 uv,它就像是幫你整理房間的魔法管家,讓每個 Python 專案都有自己整齊的「小房間」。

一、什麼是 uv?為什麼它這麼厲害?

想像一下,你的電腦就像是一個大宿舍,每個 Python 專案就像是一個學生。如果所有學生都住在同一間房間,就會很亂:

  • 小明要用 Pandas 1.5 做作業
  • 小華要用 Pandas 2.0 做專題
  • 結果兩個版本互相打架,誰的程式都跑不動!

uv 就像是宿舍管理員,它會給每個專案分配一個獨立的房間(虛擬環境),讓大家各自安心使用需要的工具。

uv 是一個用 Rust 語言製作的超快工具,它可以幫你:

  • 🏠 建立虛擬環境(取代 venv)- 就像給每個專案一個獨立房間
  • 📦 安裝和管理套件(取代 pip)- 就像幫你整理房間裡的物品
  • 🐍 管理 Python 的不同版本(取代 pyenv)- 就像準備不同年級需要的教科書
  • 🔒 建立穩定的鎖檔(lockfile)- 就像記錄每個房間裡有什麼東西
  • ⚡ 快速執行工具(取代 pipx)- 就像借用工具但不用搬到自己房間

最重要的是,uv 超級快! 官方說它比傳統方式快了 10 到 100 倍。就像從走路換成坐高鐵一樣!

image
Source

二、uv 比傳統 venv 更棒在哪?

功能傳統方法 (venv + pip)uv
速度慢,重複下載套件非常快,有快取功能
鎖檔要另外裝 pip-tools 或 poetry已經內建
版本管理要另外裝 pyenv 工具自動下載指定版本的 Python
工具執行要另外裝 pipx直接使用一次性工具執行
易用性要記很多不同工具一個工具搞定全部功能

三、為什麼每個開發者都應該養成使用虛擬環境的習慣?

🔧 真實痛點分享:我記得剛學 Python 的時候,為了做學校作業安裝了 numpy 1.19,結果同時要做另一個專案時,發現需要 numpy 1.21 才能跑。我天真地直接升級,結果之前的作業程式全部掛掉,當時真的快哭了!那時候我還不知道虛擬環境這個救星。

👥 團隊合作的慘痛經驗:和同學一起做專題時,我的電腦用 requests 2.31,他的電腦是 2.25,結果我們的 API 呼叫程式在我這邊跑得好好的,到他那邊就一直報錯。我們找 bug 找了整整一個下午,最後才發現是版本不同惹的禍!

💡 問題 1:為什麼我們需要虛擬環境?

你可以想像一下,如果你和室友共用一個書桌:

  • 你正在寫數學作業,需要計算機和直尺
  • 室友要畫圖,需要彩色筆和橡皮擦
  • 如果你們的工具混在一起,是不是很容易拿錯?

虛擬環境就像給每個人一個專屬的文具盒,這樣:

  • 數學作業不會被畫圖工具干擾
  • 每個專案都能用自己需要的「工具版本」
  • 就算安裝新工具,也不會影響到其他專案

💡 問題 2:什麼時候需要用虛擬環境?

  • 同時進行多個 Python 專案(就像同時修好幾科課程)
  • 和同學合作做專題(確保大家的「工具箱」一模一樣)
  • 想試用新套件但怕弄壞現有程式(就像想換新手機 App 但怕刪到重要資料)

💡 問題 3:建立好習慣的簡單步驟

  • 每次開新專案,第一件事就建立虛擬環境(就像搬進新房間先整理衣櫃)
  • requirements.txt 記錄需要哪些套件(就像列購物清單)
  • 記得把 .venv/ 加到 .gitignore(不要把整個房間都上傳到 GitHub)

💡 問題 4:新手常見疑問解答

Q:虛擬環境會佔用很多硬碟空間嗎? A:每個虛擬環境大約 10~30MB,就像一個小遊戲的大小,完全不用擔心!

Q:虛擬環境會不會把我的 Python 弄壞? A:絕對不會!虛擬環境就像在沙盒裡玩沙,只在自己的小天地裡運作,對外面的世界完全沒影響。

Q:忘記啟動虛擬環境怎麼辦? A:沒關係!只要重新啟動就好,就像忘記帶文具盒去教室,回去拿就好了。

小結:虛擬環境就像專屬工具箱 使用虛擬環境就像給每個專案準備一個專屬的工具箱,裡面放著這個專案需要的所有工具。這樣不同專案就不會互相干擾,也能確保和同學合作時大家用的工具都一樣。

四、超簡單的 uv 使用教學(連國中生都能學會!)

🎯 親身經歷分享:剛開始學 Python 時,光是搞懂 venv、pip、requirements.txt 這些東西就花了我好久時間。每次要開新專案都要敲一堆指令,有時候還會忘記步驟。自從用了 uv 之後,真的變得超簡單,一個指令就搞定!

以下步驟適合 Windows、macOS 和 Linux 使用者:

🚀 步驟 1:安裝 uv(只要做一次就好!)

Windows 使用者:

# 先安裝 pipx(如果還沒有的話)
pip install pipx

# 用 pipx 安裝 uv
pipx install uv

macOS 與 Linux 使用者:

# 官方推薦的安裝方式
curl -LsSf https://astral.sh/uv/install.sh | sh

💡 小提醒:就像下載 Line 或 Instagram 一樣,只要下載一次就可以一直用囉!

🏠 步驟 2:建立你的專案「小房間」

# 建立一個新的虛擬環境(就像蓋一間新房子)
uv venv

# 想要指定 Python 版本嗎?(就像選房間要幾坪大)
uv venv --python 3.12

🔑 步驟 3:進入你的專案房間

Windows 使用者:

.\.venv\Scripts\activate

macOS 與 Linux 使用者:

source .venv/bin/activate

🎉 成功指標:看到終端機前面出現 (.venv) 就表示你已經進入虛擬環境了!就像看到房門上貼著你的名字一樣。

📦 步驟 4:安裝你需要的工具(套件)

# 安裝單一套件(超快!)
uv pip install pandas

# 安裝多個套件
uv pip install pandas requests matplotlib

# 從檔案安裝所有套件(就像照購物清單買東西)
uv pip install -r requirements.txt

速度體驗分享:以前用 pip 安裝 pandas 要等 30 秒,用 uv 只要 3 秒!就像從撥接網路升級到光纖一樣爽快!

📝 步驟 5:記錄你用了哪些工具(製作清單)

# 建立套件清單(就像列出房間裡有什麼家具)
uv pip freeze > requirements.txt

# 建立更精確的鎖檔(確保每次都用相同版本)
uv pip compile requirements.in -o requirements.lock

# 依照鎖檔安裝(確保環境完全一樣)
uv pip sync requirements.lock

🛠️ 步驟 6:快速使用一次性工具

# 不用安裝就能使用工具(就像借朋友的計算機)
uv tool run black . # 格式化程式碼
uv tool run pytest # 執行測試

🎯 實用技巧:這個功能超讚!以前想用 black 格式化程式碼,還要先安裝,現在直接用就好了!


五、在不同環境使用 uv 的小技巧

🎓 在 Google Colab 使用 uv 的建議方式

雖然 Colab 無法直接使用虛擬環境(因為它本身就是個線上環境),但可以善用 uv 的快取與加速特性:

# 在 Colab 裡這樣用
!pip install uv
!uv pip install pandas numpy matplotlib

💡 小技巧:建議搭配 %%capture 抑制輸出,並於開頭一併執行,減少重複套件安裝時間。就像把購物清單一次買齊,不用每次都跑商店!

💻 在 Windows + VS Code 使用 uv 最佳實踐

這是學生和開發者最常用的組合:

  1. 開啟 VS Code Terminal:

    uv venv
    .\.venv\Scripts\activate
    uv pip install -r requirements.txt
  2. 在左下角 Python 解譯器切換到 .venv\Scripts\python.exe

  3. uv 加入 settings.json 內的 python.defaultInterpreterPath 以利預設載入

🎯 實用心得:這樣設定後,每次打開專案都會自動使用正確的 Python 環境,就像房間會自動切換到你需要的照明模式一樣方便!


六、怎麼從傳統 venv 換成 uv?

🔄 常見狀況:如果你已經習慣用 venv,沒關係!uv 很聰明,它可以跟你現有的虛擬環境和平共處。就像換了新的文具盒,舊的鉛筆還是可以用一樣!

如果你已經有 venv 的環境,完全不用重新開始:

# 在現有的虛擬環境裡,直接用 uv 安裝新套件
uv pip install 新套件名稱

# 用 uv 更新你的 requirements.txt
uv pip freeze > requirements.txt

💡 漸進式轉換小技巧:不用一次全部改掉,可以慢慢從新專案開始用 uv,舊專案照舊使用。就像換手機不用把所有照片都刪掉一樣!


七、哪些時候不適合使用 uv?

雖然 uv 很棒,但有些情況還是要用傳統工具:

  • 你的老師或主管堅持要用 Poetry(就像學校規定要穿制服一樣,沒辦法)
  • 公司專案已經用 Conda 管理科學運算套件(就像全班都在用某個 App,你也要跟著用)
  • 你需要一些特殊的 pip 參數(建議先確認 uv 是否支援)

🤷‍♂️ 實際建議:除了上述情況,大部分時候用 uv 都會讓你的開發更輕鬆!


八、如何移除 uv?

如果想要移除 uv,可執行以下步驟:

  1. 清除快取資料(非必要):
uv cache clean
  1. 刪除 uv 安裝的 Python 和工具:
rm -r "$(uv python dir)"
rm -r "$(uv tool dir)"
  1. 移除 uv 的執行檔(視安裝位置而定):
rm ~/.local/bin/uv ~/.local/bin/uvx

十、為什麼資深 Python 開發者會愛用 uv?

以下透過實際範例比較,說明 uv 為什麼更受資深開發者喜愛:

以下透過實際範例比較,說明 uv 為什麼更受資深開發者喜愛:

🆚 傳統方式

# 建立虛擬環境
python -m venv .venv
source .venv/bin/activate

# 安裝套件
pip install -r requirements.txt

# 建立鎖檔
pip install pip-tools
pip-compile requirements.in
pip-sync requirements.txt

✅ 使用 uv 的方式

# 建立虛擬環境(若沒安裝過指定版本會自動處理)
uv venv --python 3.11

# 安裝套件
uv pip install -r requirements.txt

# 鎖檔與同步
uv pip compile requirements.in -o requirements.lock
uv pip sync -r requirements.lock

✅ 其他實用命令

# 快速執行一次性工具,不汙染環境
uv tool run black .

# 移除全部快取與工具
uv cache clean

✅ 為什麼資深開發者會選 uv?

  • 節省時間:省略繁瑣安裝流程,一鍵完成
  • 減少工具切換:整合 venv、pip、pip-tools、pyenv、pipx
  • 更穩定:官方支援、鎖檔清楚、快取合理
  • 適合團隊:易於寫入 CI/CD,也適合教新手快速入門

根據官方說明與實務觀察,資深開發者選擇 uv 通常有以下幾個原因:

  • 速度就是生產力:uv 利用 Rust 高效處理封裝、快取與安裝,極大減少套件安裝與環境建立時間。
  • 整合工具多合一:uv 同時整合 venvpippip-toolspipxpyenv 的功能,一套工具即可搞定開發日常。
  • 強大的可重現性:內建 compilesync 機制,能保證部署時環境一致、版本鎖定穩定。
  • 自動管理 Python 版本:不必額外裝 pyenv,uv 可直接下載並使用特定版本的 Python,方便管理多版本開發需求。
  • 適合 CI/CD 與 Docker:uv 是單一可執行檔,非常容易整合到自動化流程,避免繁瑣相依設定。

這些優點讓資深開發者能更快速部署、更輕鬆維護專案環境。


⛓ 自動管理 Python 版本示範

uv 可以幫你自動下載與管理所需的 Python 版本,無需另外安裝 pyenv:

# 安裝指定版本的 Python(若尚未存在)
uv python install 3.11

# 建立虛擬環境,並自動使用該版本
uv venv --python 3.11

透過這方式,開發者在不同專案間可以快速切換對應版本,避免「系統版本不同」導致出錯。


⚙️ 在 CI/CD 與 Docker 中使用 uv 的範例

GitHub Actions CI 範例:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: 安裝 uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh

- name: 安裝相依套件
run: uv pip install -r requirements.txt

- name: 執行測試
run: uv run pytest

Dockerfile 範例:

FROM python:3.11-slim

# 安裝 uv
RUN curl -LsSf https://astral.sh/uv/install.sh | sh

# 設定工作資料夾
WORKDIR /app
COPY . .

# 安裝套件
RUN uv pip install -r requirements.txt

CMD ["uv", "run", "python", "main.py"]

這讓部署流程更加簡潔、快速,特別適合雲端平台或自動測試環境。


結語

🔍 我自己的使用心得:以前我會忘記啟動虛擬環境,或裝在錯的地方,導致電腦裡的套件亂七八糟。自從開始用 uv 後,流程變得簡單不易出錯,尤其在教學生或帶新手時更順利。

uv 速度快又簡單,是 Python 開發的新好朋友。趕快試試看吧!

更多資訊:uv 官方 GitHub

· 2 min read
Willis Chen

image

介紹

在這篇文章中,我們將探討如何使用 GitHub Codespace 快速有效地建立和部署 LINE Bot。GitHub Codespace 提供了一個雲端開發環境,使得開發人員可以在任何地方進行開發和部署。這種方式的好處是不需要本地環境配置,且環境變數的設置增加了項目的安全性。

步驟一:設置 GitHub Codespace

首先,你需要在 GitHub 上啟用 Codespace 並克隆你的專案。

  1. 登入你的 GitHub 帳號。
  2. 找到你的專案倉庫,點擊 "Code" 按鈕,選擇 "Open with Codespaces"。
  3. 選擇 "New codespace" 來建立一個新的開發環境。 image

步驟二:設置環境變數

在 Codespace 中設置你的 LINE Bot 的環境變數:

  1. 創建一個 .env 檔案。

  2. 加入以下環境變數:

    LINE_CHANNEL_SECRET=你的channel_secret
    LINE_CHANNEL_ACCESS_TOKEN=你的access_token
  3. 在這個示範專案,可以將MediaSystem-Python-Course\06.Line-bot-fly-flask\config-templete.py另存為config.py,也就是環境變數儲存在config.py的檔案裡,這是一個簡易用法不建議正式使用,使用環境變數對機密資訊才有較佳的保護。

步驟三:安裝依賴

在 Codespace 的終端機運行以下命令安裝所需依賴:

pip install -r requirements.txt

步驟四:編輯程式碼

使用 GitHub Copilot 來協助編寫和優化程式碼。例如,以下是一個簡單的 Flask 應用來回應 LINE Bot 的訊息:

from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage

app = Flask(__name__)

line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')

@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token, TextSendMessage(text=event.message.text))

if __name__ == "__main__":
app.run()`

步驟五:測試與部署

啟動你的 Flask 應用並進行測試。你不需要使用 ngrok 來建立 TLS 認證。

  1. 在 Codespace 的終端機運行你的 Flask 應用。
  2. 使用 LINE Bot 進行測試,確保一切運行正常。

結語

使用 GitHub Codespace 來建立和部署 LINE Bot 是一個高效且安全的方法。這種方式不僅節省了設置本地開發環境的時間,還提供了一個穩定和安全的開發平台。希望這篇文章能夠幫助你順利完成 LINE Bot 的開發和部署。

· 9 min read
Willis Chen

老師們現在不僅對教學充滿熱情,也愈來愈善於運用科技工具,如LINE官方帳號,來與學生和家長保持緊密的溝通。這些努力無疑是朝著以下兩大目標邁進:

  1. 激發學生的好奇心:鼓勵學生主動提問,並引導他們思考解決問題的方法。
  2. 個別化教學:深入了解每位學生的學習進度和思維方式,以因材施教。

🤖 專案介紹

這個專案的核心目的是要讓老師們能在已有的LINE官方帳號上,快速加入一個AI助教—使用ChatGPT技術。這樣一來,AI助教能夠第一時間回應學生的問題,如果遇到AI不能解決的問題,它還會建議學生直接聯繫老師。這讓老師有更多的時間和空間來專注於其他重要的教學任務。

🛠️ 如何開始?

這個專案極力降低相關的技術門檻。實際上,在幾乎不需要寫任何程式碼的情況下,老師就能設置起這個AI助教服務。你只需完成以下幾個簡單的步驟:

  1. 註冊本服務
  2. 在LINE官方帳號後台進行相應設定
  3. 啟用ChatGPT作為你的AI助教

完成以上步驟後,你就能讓ChatGPT開始擔任你的AI助教,預先回答學生的問題。

👉 歡迎各位老師運用,打造更智慧、更高效、教學相長的教學環境!

📚 在開始之前,你需要了解的

在你開始使用這個專案之前,有一些基礎的技術和費用信息你需要知道。

技術環境

  • 涉及的技術和環境如下:
    • 程式語言: Python
    • 伺服器後端框架: Flask
    • FaaS雲端服務: Vercel
    • AI對話功能: OpenAI API (ChatGPT-3.5-tubo)
    • 聊天環境: LINE (LINE Message API)

花費預估

  • Vercel

    • Hobby方案允許你免費建立最多3個專案。
    • 注意:如果伺服器處理時間超過10秒,將會被判定為Time Out。
    • Vercel 費用詳情
  • OpenAI API

    • 初次註冊有免費額度,API使用需綁信用卡。
    • 本專案預設使用的是2023/11釋出的 GPT-4-1106-preview
    • OpenAI 費用詳情
    • OpenAI Cost
  • LINE 主動訊息

    • 額度內免費,目前是200則訊息(2023/9月前為500則)。
    • 由使用者提問的回覆(Reply)免費。
    • 老師主動發送的訊息(Push)有200則限制。
    • LINE 費用詳情
    • LINE Cost1
    • LINE Cost2

    提醒您: 所有的費用和限制可能會隨著各個服務供應商的政策改變而變動,建議定期查看官方網站以獲取最新資訊。

如何建立自己的 LINE AI助教?

這份指南將引領您從LINE 官方帳號開始,不同於開發者通常從 LINE Developers 開始。不過,不管從哪裡出發,最終目標相同:建立一個集成 ChatGPT 的 LINE 官方帳號。

🌟 步驟1:初始化 LINE 官方帳號 🌟

首先,我們需要建立一個基本的、無AI功能的 LINE 官方帳號。學生們可以即刻加入這個帳號。這個帳號初期僅支持手動聊天,AI 功能將在後續逐步加入。

  1. 前往 LINE 官方帳號管理頁面

  2. 填寫必要資訊:這些資訊也會是學生看到的名稱。

  3. 選擇「稍後認證官方帳號」:這個認證過程不會影響本專案。

  4. (選擇性)建立圖文選單:利用圖文選單可提供班級公告、相片集等。

    • 主頁 > 圖文選單 > 參考說明
  5. 啟用 Webhook 🔗

    • Webhook 是一個可用程式處理訊息的通道。
    • 通過 Webhook,我們將使用 Vercel 平台、Python Flask 框架和 OpenAI API。

🌟 步驟2:註冊必要的平台並獲取 API Token

  1. 註冊必要平台:包括 GitHubVercelOpenAI APILINE Developers
  2. 獲取 OpenAI API Token:保存好這個 Token,它是一次性的。

🌟 步驟3:設置 LINE Developer Channel 及獲取 Secret, Token 🌟

3.1 獲取 Channel Secret 🔒

  • 從 LINE 官方帳號或 LINE Developer Channel 都可獲取。

3.2 獲取 Channel Access Token 🔑

  • 在 LINE Developer Channel 下生成。

🌟 步驟4:Fork GitHub 專案 🌟

  • Fork 這個專案至您自己的 GitHub 儲存庫。

🌟 步驟5:部署至 Vercel 🌟

  1. 建立 Vercel 專案
  2. 連接 GitHub 和選擇專案
  3. 設定環境變數並部署
  • 您需要設定的環境變數為OPENAI_API_KEYLINE_CHANNEL_ACCESS_TOKENLINE_CHANNEL_SECRET,在這裡的環境變數能受到較佳的保護,至少比放在程式碼裡安全許多。

  1. 修正支援的Nodejs版本
  • 如果遇到Python安裝版本問題,依據官方文件,Vercel預設的Node.js版本為20.x,不支援Python,請在專案的設定>一般的選項裡,將Node.js改選為18.x版本。 image

  • 修改後請選擇部署,或到專案的佈署歷程中選擇再次部署,就會改用Node.js 18.x版再跑一次。 image

🎉 完成! 🎉

恭喜您,現在您已經成功建立了自己的 AI 助教!現在可以透過 LINE 官方帳號進行測試。

🔧 進階設定:打造個性化的AI助手

  • 若要讓AI助手更符合你的需求和風格,OpenAI API提供了一個彈性的方式讓你自行設定AI的角色。具體來說,你只需要在對話設定中添加 messages: [{ role: "system", content: "你的AI助手人設" }] 即可。
  • 進行這項設定只需前往api/prompt.py並在AI_GUIDELINES後修改提示文字即可。不過,因為Vercel的免費版有10秒的運行時限制,過長的提示可能會導致Time Out,因此建議不要設置過於複雜的指引。
  • 本專案經過精心測試後,已經內建一組最佳實踐的AI_GUIDELINES,但你也可以隨心所欲地進行調整:
    AI_GUIDELINES = '你是一個AI助教,專門使用蘇格拉底教學法來回答學生的問題,如果有需要,會建議學生與老師進一步確認。'
  • 修改方式也非常簡單,只需登入你的GitHub帳號,找到該專案的api/prompt.py文件,點擊右側的鋼筆圖示✏️即可進行線上編輯。 編輯
  • 完成後,選擇“Commit Changes”並填入適當的描述。 提交更改 描述

🚀 專案成果

  • 出色的問答回應: 這個AI助手自2023年11月7日OpenAI大幅降低費率後,採用GPT 4模型,更能通順的、即時地回應學生的問題。 出色回應

  • 問題過濾: 對於需要更深層次討論的問題,AI助手會提供適當的處理建議,協助老師過濾和分類問題,同時也啟發老師改進教學。 問題過濾

  • 引導學生思考: 透過蘇格拉底教學法,AI助手不僅回答問題,還能引導學生學會如何提問和解決問題。

    同學A 老師我想要問BMI的python程式怎麼寫
    ----
    AI助教 嗨!關於BMI的Python程式,我可以幫你一起思考。首先,你知道BMI是什麼嗎?
    ----
    同學A BMI=體重/身高平方
    ----
    AI助教 沒錯!BMI是體重除以身高的平方。那麼,你想要寫一個計算BMI的Python程式對吧?你已經有身高和體重的數值了嗎?
    ----
    同學A 70/(1.73**2)
    ----
    AI助教 沒錯!你可以使用這個公式來計算BMI。現在我們可以開始寫一個Python程式來計算BMI。你想要將身高和體重作為變數輸入嗎?
    ----
    同學A 想
    ----
    AI助教 好的!我們可以寫一個簡單的Python函數來計算BMI。以下是一個範例程式碼:

    ```python
    def calculate_bmi(weight, height):
    bmi = weight / (height ** 2)
    return bmi

    weight = float(input("請輸入您的體重(公斤):"))
    height = float(input("請輸入您的身高(公尺):"))

    bmi = calculate_bmi(weight, height)
    print("您的BMI為:", bmi)
    ```

    這個程式會要求使用者輸入體重和身高,然後使用`calculate_bmi`函數計算BMI並輸出結果。請注意,身高的單位應該是公尺,體重的單位應該是公斤。
    ----
    同學A 請幫我也寫出測試碼,之後會用pytest測試
    ----
    AI助教 當然!我們可以寫一些測試碼來驗證我們的BMI計算函數是否正確。以下是一個範例的測試碼:

    ```python
    import pytest

    def calculate_bmi(weight, height):
    bmi = weight / (height ** 2)
    return bmi

    def test_calculate_bmi():
    assert calculate_bmi(70, 1.73) == pytest.approx(23.39, 0.01)
    assert calculate_bmi(80, 1.65) == pytest.approx(29.38, 0.01)
    assert calculate_bmi(60, 1.80) == pytest.approx(18.52, 0.01)

    if __name__ == "__main__":
    pytest.main()
    ```

    這個測試碼使用了pytest套件來執行測試。我們定義了一個`test_calculate_bmi`函數,其中包含了幾個斷言語句,用來驗證`calculate_bmi`函數的輸出是否符合預期。每個斷言語句都使用了`pytest.approx`函數來比較浮點數的近似值,並指定了一個容忍誤差範圍。

    你可以將這個測試碼保存為一個.py檔案,然後使用pytest運行測試。如果所有的測試通過,則表示你的BMI計算函數正確無誤。
    ----
    同學A 謝謝老師,我的超人
    ----
    AI助教 不客氣!如果你有任何其他問題,隨時都可以問我。祝你一切順利!

    培養思考 成果展示 更多示例

專案成果

  1. 出色的回應學生問題: 這個功能不僅可以即時解答學生的問題,還可以減輕老師的負擔。
  2. 過濾問題: 能過濾並指導學生如何更有效地提問,是一個對教師非常有幫助的功能。
  3. 引導學生思考: 這是最讓人印象深刻的部分,因為不僅解答了問題,還教會了學生如何解決問題。

這個專案不僅具有高度的實用性,也很有教育意義。它不只是一個問答工具,更是一個能夠協助教學和學習的平台。

參考資料

· 4 min read
Willis Chen

🐍 Python 是一種非常流行和強大的程式語言,它有許多優秀的套件可以幫助我們完成各種任務,例如資料分析、機器學習、網頁開發等。然而,如果我們同時在不同的專案中使用 Python,我們可能會遇到一些問題,例如:

  • 不同的專案可能需要不同的 Python 版本或套件版本,這可能會造成版本衝突和相依性問題。
  • 如果我們在全域環境中安裝或移除套件,可能會影響其他專案的運作。
  • 如果我們想要部署或分享我們的專案,我們需要記錄和安裝所有需要的套件和版本,這可能會很麻煩和耗時。

為了解決這些問題,我們可以使用虛擬環境管理工具來創建和管理不同的 Python 環境。虛擬環境是一個隔離的 Python 環境,它可以讓我們在不同的專案中使用不同的 Python 版本和套件,而不會互相干擾。這樣,我們就可以更方便和安全地開發和部署我們的 Python 專案。

目前,有許多虛擬環境管理工具可以選擇,例如 virtualenv, conda, pyenv 等。在這篇文章中,我將重點介紹 pipenv 和 venv 這兩種工具,並且比較它們的優缺點。

pipenv

  • pipenv 是目前 Python 官方推薦的套件管理工具,它集成了 pipvirtualenv 的功能,並且改進了它們的一些缺陷 。
  • pip 使用 PipfilePipfile.lock 來記錄套件的資訊,而不是使用 requirements.txt。
    • Pipfile.lock 包含了套件的Hash值,可以確保安裝的套件是一致和安全的 。
    • pipenv 可以自動產生和更新 PipfilePipfile.lock,不需要手動維護 。
  • 可以區分開發和生產環境的套件,只需要在安裝時加上 --dev 參數即可 。
  • 可並行(parallel)同步安裝套件,提升安裝速度。
  • pipenv 可以透過 .env 自動載入不同環境變數。
  • pipenv 的指令比較簡單和直觀,例如
    • pipenv install 如同 pip install
    • pipenv uninstall
    • pipenv shell 如同 source venv/bin/activate 進入虛擬環。
    • pipenv run 可以執行虛擬環境內容

venv

  • venv 是 Python 3.3 之後內建的虛擬環境模組,它可以創建一個隔離的 Python 環境,但是不包含任何套件管理功能。
  • venv 使用 python -m venv {虛擬機命名} 來創建虛擬環境,然後使用 source venv/bin/activate 來啟動虛擬環境(Windows 以 venv/Scripts/activate 進入)。
  • venv 需要配合 piprequirements.txt 來管理套件,因為venv跟pip是兩回事,這可能會造成版本衝突和相依性問題。

比較 pipenv 和 venv 差異

以下用表格比較 pipenv 和 venv 的差異,我用表格的方式來比較它們的特點:

特點pipenvvenv
Python 官方推薦曾經是
集成 pip 和 virtualenv
使用 Pipfile 和 Pipfile.lock
自動產生和更新 Pipfile 和 Pipfile.lock
包含套件的哈希值
區分開發和生產環境的套件
使用並行同步安裝套件
自動載入不同環境變數
指令簡單和直觀

從表格中,我們可以看出 pipenv 是一個更先進和完善的虛擬環境管理工具,它可以讓我們更方便和安全地開發 Python 專案。如果你想了解更多關於 pipenv 的資訊,但在基礎Python教學時,我更傾向以venv為主,因為你看到的網路專案大多還是venv + pip install -r requirements.txt 來示範的。可以參考以下的連結:

感謝你閱讀這篇文章,如果你有任何問題或建議,歡迎在下方留言。Enjoy Python。再見!

· 2 min read
Willis Chen

如果你對如何將 LINE 聊天機器人與 HackMD 結合有興趣,這篇文章正是你需要的。這次,我們將使用 Render 這個雲端平台來部署我們的應用。

前置作業:準備你的 GitHub 倉庫

  1. Fork 專案:首先,請到這個 GitHub Repo 進行 fork,這樣你就有了一個屬於自己的副本。

    Fork Repo

Render 設定

登入和選擇服務

  1. 登入 Render:前往 Render 的網站 並用 GitHub 帳號登入。

    登入 Render

  2. 選擇 Web 服務:在 Render 的 dashboard,選擇 "Web Service"。

    選擇 Web Service

設定部署參數

  1. 基本設定:填入應用的名稱和其他基本資訊。在這裡,我們選擇免費的方案。如果你的主程式檔名不是 app.py,記得修改 gunicorn 的指令。

    基本設定 更多設定

  2. 設定環境變數:在 .env 檔案中填入所有需要的環境變數。

    環境變數設定

  3. 等待部署完成:設定完成後,Render 會自動進行部署。

    部署狀態

需要的 API 金鑰和資訊

HackMD API

  • 請參考 HackMD 的官方文件以獲得 API 金鑰。

OpenAI API

  1. 訪問 OpenAI API 官網

  2. 生成一個一次性的 API 金鑰。注意:一旦關閉視窗,這個金鑰將不再顯示。

    OpenAI API API 金鑰

LINE Message API 和 Imgur API

  • 請依照各自平台的文件申請 API 金鑰。

環境變數在 Python 中的使用

你可以使用以下程式碼來讀取環境變數。

import os
api_key = os.environ.get('KEY')`

配置 LINE Webhook

最後,回到 LINE Channel 設定中加入 webhook。

LINE Webhook

這樣你就完成了整個部署過程!如果你有任何問題或建議,歡迎在下方留言。祝學習愉快!

· 3 min read
Willis Chen
  • Selenium 是一個自動化測試框架,專門用於測試 Web 應用程式。作為一位經常需要隨著套件更新來調整教學內容的講師。將針對最近升級至 4.x 版本的 Selenium 進行比較,以及如何解決版本更新的程式碼問題。

預期 Selenium 版本更新會遇到的狀況

在過去,我預期會遇到以下幾種情況:

  • 需要更新至新版的 webdriver。
  • 程式參數更新,需要查看 log 以解決問題。

然而,升級至 Selenium 4.x 後,我發現了一些令人驚喜的改變。

1. webdriver管理更聰明了

舊版流程

在 Selenium 4.x 版本之前,安裝 Selenium 是一件相對繁瑣的事情。你需要:

  1. pip install 安裝 Selenium 主要套件。
    pip install selenium
  2. 然後,你還需要手動下載與你的 Chrome 版本相對應的 WebDriver。
  3. 解壓縮 WebDriver,然後將其放入指定目錄。

過渡版本- 需額外的 webdriver_manager

  • 在2023年之前的一段時間簡化了上述流程,透過pip install webdriver_manager直接安裝好對應的測試瀏覽器,不用找對應的瀏覽器與版本,但需要引入webdriver_manager套件。

    pip install webdriver_manager
  • 然後,使用webdriver_manager的範例如下:

    from selenium import webdriver
    from webdriver_manager.chrome import ChromeDriverManager

    options = webdriver.ChromeOptions()
    # options.add_argument('--headless')

    wd = webdriver.Chrome(ChromeDriverManager().install(), options=options)
    wd.get("https://www.google.com")
    wd.save_screenshot("google_homepage.png")
    wd.quit()

新版流程

  • 現在,在 Selenium 4.x 版本,你只需執行一個指令即可:

    pip install selenium
  • 這個改變意味著,你不再需要手動去管理 WebDriver,Selenium 會為你處理一切。

2. selenium.webdriver.Chrome()`參數簡化

舊版用法

  • 在舊版中,初始化 Chrome WebDriver 的代碼通常會看起來像這樣:

    from selenium import webdriver

    options = webdriver.ChromeOptions()
    options.add_argument('--headless')

    wd = webdriver.Chrome('path/to/chromedriver', chrome_options=options)

新版用法

  • 在新版中,由於 WebDriver 已經被整合,你可以簡單地這樣做:

    from selenium import webdriver

    options = webdriver.ChromeOptions()
    options.add_argument('--headless')

    wd = webdriver.Chrome(options=options)

Selenium 搜尋 PTT 指定列表範例

如你所見,新版省去了指定 chromedriver 路徑的需求,使得代碼更為簡潔,最後分享一個這學期調整的selenium範例:

from selenium import webdriver
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup


def make_webdriver() -> Chrome:
options = create_options()
driver = Chrome(options=options) #簡化參數
return driver


def create_options() -> Options:
options = Options()
options.add_argument("--headless")
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument("--start-maximized")
return options


def get_ptt_board_list(board) -> list:
url = f"https://www.ptt.cc/bbs/{board}/index.html"
wd = make_webdriver()
wd.get(url=url)
soup = BeautifulSoup(wd.page_source,"html.parser")
links = soup.select('div.title > a')
res = [{
'title': link.get_text(),
'href': f'https://www.ptt.cc{link.get("href")}'
} for link in links if '公告' not in link.get_text() ]
wd.quit()
return res

if __name__ == '__main__':
res = get_ptt_board_list('movie')
print(res)

小結

Selenium 4.x 版本帶來了許多便利性的提升,尤其是在 WebDriver 管理和參數簡化方面。這對於減少教學備課的負擔以及提高自動化測試的效率都有很大的幫助。

我個人非常推薦升級至這個版本,以便能夠利用這些新的特性和優化。

· 5 min read
Willis Chen

在這篇文章中,將探討如何使用Python的PlayWright模組來抓取巴哈姆特動漫瘋的彈幕數據。 目標如下:

  • 認識PlayWright
  • 如何安裝PlayWright。
  • 如何利用PlayWright控制網頁行為。
  • 如何改寫腳本,抓取、整理和儲存需要的數據。

什麼是PlayWright?

PlayWright 是Microsoft推出的開源專案,是一個Python用戶端,讓我們能夠自動化Web瀏覽器的行為,包括Chrome, Firefox, 和Safari等主流瀏覽器。你可以使用它來進行網站測試、抓取資料,甚至製作自動化的網頁腳本。透過PlayWright,你能控制整個瀏覽過程,包括產生彈幕等動態內容。

如何安裝PlayWright

安裝PlayWright相當簡單,只需要在你的命令列工具 (例如:終端機或Command Prompt) 輸入以下命令即可:

> pip install playwright

如何利用PlayWright控制網頁行為

首先,我們需要啟動一個PlayWright的實例,並且以我們選定的瀏覽器來執行我們的程式。以下是一個以Chromium瀏覽器為例的程式碼,同理也可以使用webkit瀏覽器:

> python -m playwright codegen -b chromium

執行上述命令後,您將開啟一個Chromium瀏覽器並開始與其互動。你的每一個操作,都會自動生成對應的Python程式碼。

codegen命令包含一些可用的參數,例如:

  • --target: 設定你的程式語言,如 python、JavaScript等。
  • -o: 指定存放生成程式碼的檔案名稱。
  • -b: 選擇你想要使用的瀏覽器,如 chromium、firefox或webkit。

以下是一個實際的例子,使用webkit瀏覽器抓取巴哈姆特動漫瘋網站並將程式碼儲存在damun.py文件中:

> python -m playwright codegen --target python -o damun.py -b webkit https://ani.gamer.com.tw/

此時的damun.py內容參考如下:


from playwright.sync_api import Playwright, sync_playwright
from bs4 import BeautifulSoup
import json
import sys
import time


def run(playwright: Playwright, sn) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()

page.goto(f"https://ani.gamer.com.tw/animeVideo.php?sn={sn}")
time.sleep(5)

# screenshot
page.screenshot(path='ani.jpg', full_page = True)

### 稍後加上網頁解析
### 稍後加上內容萃取
### 稍後加上資料儲存

page.close()

# ---------------------
context.close()
browser.close()


with sync_playwright() as playwright:
run(playwright, sys.argv[1])

修改PlayWright腳本

為了包含抓取後的解析及整理,可以在前面透過點選產製的damun.py腳本中,新增解析的程式

  • 網頁解析: page內容為HTML,將其轉換成BeautifulSoup物件,方便後續操作。

    from bs4 import BeautifulSoup

    soup = BeautifulSoup(page.content(), 'lxml')
  • 內容萃取: 這邊藏的一個很關鍵的做法,用For迴圈直接將結果設計為JSON like的Python Dictionary格式。

    • 每次回圈的過程一次性的將擷取對象整理好。
      # for-loops
      res = []
      k = {}
      for li in soup.select('.sub-list-li'):
      k['userid'] = li.select_one('.name > span').text.strip()
      k['text'] = li.select_one('.sub_content').text.strip()
      k['msg_time'] = li.select_one('b').text.strip()
      print(k)
      res.append(k)
    • 如果你熟悉列表推導式(list comprehension),以下改寫更為直觀:
          res = [ {
      'userid': li.select_one('.name > span').text.strip(),
      'text' : li.select_one('.sub_content').text.strip(),
      'msg_time' : li.select_one('b').text.strip()
      } for li in soup.select('.sub-list-li')]
  • 資料儲存: 將Dict樣式存成JSON格式,方便後續運用。

    import json

    with open(f'damun_{sn}.json', 'w') as f:
    json.dump(res, f)
  • 最終的damun.py腳本內容:


from playwright.sync_api import Playwright, sync_playwright
from bs4 import BeautifulSoup
import json
import sys
import time


def run(playwright: Playwright, sn) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()

page.goto(f"https://ani.gamer.com.tw/animeVideo.php?sn={sn}")
time.sleep(5)

# screenshot
page.screenshot(path='ani.jpg', full_page = True)

# 網頁解析
soup = BeautifulSoup(page.content(), 'lxml')

# 內容萃取(列表推導式)
res = [ {
'userid': li.select_one('.name > span').text.strip(),
'text' : li.select_one('.sub_content').text.strip(),
'msg_time' : li.select_one('b').text.strip()
} for li in soup.select('.sub-list-li')]

print(res)


# 資料儲存(JSON檔)
with open(f'damun_{sn}.json', 'w') as f:
json.dump(res, f)

page.close()

# ---------------------
context.close()
browser.close()
return res


with sync_playwright() as playwright:
run(playwright, sys.argv[1])

執行playwright腳本

接下來,執行我們生成的腳本,可以在命令列執行腳本。

33846為動畫的編號,可以更換成想要分析的動畫序號。

python damun.py 33846

然後,使用Python的ast模組將結果轉換為Python對象。以下是一個實際的例子:

# 此欄位內容於ipynb執行
res = ! python damun.py 33846
import ast
res = [ast.literal_eval(i) for i in res]
print(res)

將內容存為page.json

有兩種方式可以將我們獲得的結果儲存為json格式。一種方式是使用linux的命令行將結果重定向到一個json檔案中。例如:

> python damun.py 33846 > page.json

另一種方式是直接在Python腳本中將結果儲存為json檔案。以下是一個實際的例子:

import json

file_name = 'damun_33846.json'

with open(file_name, 'r', encoding='utf-8') as f:
my_data = json.loads(f.read())

print(my_data)

print(type(my_data))

解析的結果為:

擷取完成!

重點精華

  • PlayWright可以輕鬆的將使用者操作流程紀錄為程式碼。
  • PlayWright與Selenium最大的差異,不用刻意搜尋並安裝對應版本的模擬瀏覽器。
  • 結合常用的Beautiful可以快速解析內容,我偏好用類似CSS Selec。
  • 用列表推導式將爬梳的資料整理成字典,語法相當簡潔。
  • 將結果儲存成JSON2檔案,方便後續運用

小結

在上述的Python腳本中,首先定義了我們的檔案名稱。然後,我們使用Python的內建函數open讀取該檔案。最後,我們使用json模組的loads函數將讀取到的資料轉換為Python物件。

以上就是如何使用PlayWright抓取並分析巴哈姆特動漫瘋的彈幕數據的全過程。透過這個過程,我們不僅學習到如何使用PlayWright,如果有興趣,後續再介紹如何進一步分析數據,歡迎留言讓我知道。