跳至主要内容

7 篇文章 含有標籤「html」

檢視所有標籤

LangGraph 入門教學筆記:打造多步驟 AI 流程的圖形化解決方案 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

隨著生成式 AI 的應用越來越廣泛,從客服機器人、智慧問答系統到複雜的自動化工作流程,開發者面臨的不再只是單次的文字生成,而是需要處理多步驟的對話邏輯與決策流程

傳統上,這類應用通常透過繁瑣的 if-else 邏輯、狀態機或多層函式巢狀處理,程式碼不易閱讀與維護。為此,LangGraph 應運而生。它是一個開源的 Python 函式庫,讓開發者可以用「流程圖」的方式清晰地定義每一步的處理邏輯,進而打造更穩定且模組化的 AI Workflow。


重點摘要

  • LangGraph 是什麼?

    • 由 LangChain 團隊開發的 AI Workflow 工具,透過流程圖(Graph)定義多步驟的推理過程。
    • 每一個節點(Node)代表一個處理步驟,從 LLM 回覆、條件判斷到工具呼叫等皆可定義成節點。
  • 核心特色

    • 使用有向圖(DAG)表示流程,每個節點都有明確的輸入與輸出狀態。
    • 支援條件分支、迴圈、自訂狀態、記憶上下文。
    • 可與 LangChain、OpenAI、Anthropic 等服務整合。
    • 適合用於構建 Agent、Chatbot、多階段處理流程。
  • 應用情境

    • 客製化對話代理人(如智能客服)
    • 多階段資訊處理(如:檢索、分類、摘要)
    • 工具選擇與執行流程(如:根據輸入選擇工具)
    • 擴展型 LLM 應用(如:RAG、Tool Use)
  • 重要元件說明

    • StateGraph:定義整體流程圖。
    • Node:每個節點代表一個具邏輯意義的步驟。
    • State:儲存目前上下文狀態,可自訂欄位。
    • Conditional Edge:根據邏輯結果決定下一個節點。

實際範例:打造一個 FAQ 對話機器人

本範例將建立一個簡單的對話流程:

  1. 使用者輸入問題。
  2. 呼叫 OpenAI GPT 模型回覆。
  3. 若輸入為 "bye",流程結束;否則持續對話。

1. 安裝套件

pip install langgraph langchain openai

2. 定義狀態與回應節點

from langgraph.graph import StateGraph, END
from langchain.chat_models import ChatOpenAI
from typing import TypedDict

# 自訂狀態格式
class ConversationState(TypedDict):
messages: list[str]
last_user_input: str

# 初始化 LLM
llm = ChatOpenAI(model="gpt-4", temperature=0)

# 處理回應的節點
def generate_response(state: ConversationState):
user_input = state["last_user_input"]
state["messages"].append(f"User: {user_input}")
response = llm.predict(f"請回答以下問題:{user_input}")
state["messages"].append(f"AI: {response}")
return state

3. 定義流程結束條件與流程圖

# 判斷是否要結束對話
def should_continue(state: ConversationState):
if state["last_user_input"].lower().strip() == "bye":
return END
return "generate"

# 建立流程圖
builder = StateGraph(ConversationState)
builder.add_node("generate", generate_response)
builder.set_entry_point("generate")
builder.add_conditional_edges("generate", should_continue)

graph = builder.compile()

4. 執行對話流程

# 初始狀態
state = {
"messages": [],
"last_user_input": "你好,這是什麼系統?"
}

# 執行第一輪
state = graph.invoke(state)

# 模擬第二輪
state["last_user_input"] = "LangGraph 是什麼?"
state = graph.invoke(state)

# 模擬結束對話
state["last_user_input"] = "bye"
state = graph.invoke(state)

# 印出對話記錄
for msg in state["messages"]:
print(msg)

範例輸出結果

User: 你好,這是什麼系統?
AI: 這是一個由 LangGraph 架構的對話系統。
User: LangGraph 是什麼?
AI: LangGraph 是一個讓開發者用流程圖方式設計 AI 應用的工具。
User: bye
AI: 感謝使用,祝您有美好的一天。

總結與延伸

LangGraph 為 LLM 應用程式帶來一個明確的結構化框架,讓我們能夠模組化管理多步驟流程、狀態記憶與條件判斷。相較於傳統方式,它更適合用來構建複雜、可維護的對話式 AI 應用。

延伸應用可以包括:

  • 整合 LangChain 工具(如:向量資料庫、搜尋引擎)
  • 建構具有分支與回饋機制的智能 Agent
  • 開發能根據上下文自我修正的 RAG 系統
  • 將整個 LangGraph 部署為 Web API 或背景工作流程

參考文件

  1. LangGraph: LangChain Agent 的殺手鐧 (入門)

useSWR 入門教學筆記:打造高效、簡潔的資料請求方式 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在現代前端開發中,資料的取得與管理是不可或缺的一環。傳統上,我們可能使用 useEffect 搭配 fetchaxios 來處理資料請求,但這樣的方式不僅冗長,還需要手動管理 loading、error 狀態與快取邏輯。為了解決這些問題,Vercel 推出的 SWR(stale-while-revalidate)提供了一種簡潔、聲明式且高效的資料取得方式,特別適合搭配 React 應用開發。

本文將介紹 SWR 的核心觀念、使用方式與基本範例,幫助我們快速上手並應用於實務開發中。


重點摘要

  • SWR 是什麼?

    • SWR 是由 Vercel 開發的 React Hooks 函式庫,提供資料快取與同步機制。
    • 名稱來自 HTTP 快取策略 “stale-while-revalidate”,意指:先顯示舊資料,再重新驗證更新資料
  • 為什麼要使用 SWR?

    • 自動處理資料快取與重新驗證。
    • 簡化資料請求邏輯,減少樣板程式碼。
    • 支援多種進階功能(錯誤重試、revalidate on focus、polling 等)。
  • 基本用法

    • 使用 useSWR(key, fetcher) 進行資料請求。
    • key:唯一識別資料來源的 key,通常為 API 路徑。
    • fetcher:資料請求函式,可使用 fetchaxios 實作。
  • 常見功能

    • isLoadingerror 狀態管理。
    • 自動重試與重新整理資料。
    • 快取與全域共用資料(Shared cache)。
    • 手動重新驗證資料(revalidate)。
    • 支援 SSR、Pagination、Mutation 等進階功能。

實際範例:取得 GitHub 使用者資料

1. 安裝 SWR

npm install swr
# 或使用 yarn
yarn add swr

2. 撰寫 fetcher 函式

// libs/fetcher.ts
export const fetcher = (url: string) => fetch(url).then((res) => res.json());

3. 在元件中使用 useSWR

// pages/UserProfile.tsx
import useSWR from 'swr';
import { fetcher } from '../libs/fetcher';

const UserProfile = () => {
const { data, error, isLoading } = useSWR('https://api.github.com/users/octocat', fetcher);

if (isLoading) return <div>載入中...</div>;
if (error) return <div>載入失敗:{error.message}</div>;

return (
<div>
<h1>{data.name}</h1>
<p>GitHub:{data.login}</p>
<p>Followers:{data.followers}</p>
<img src={data.avatar_url} width={100} />
</div>
);
};

export default UserProfile;

4. 手動重新驗證資料

const { data, mutate } = useSWR('/api/data', fetcher);

// 手動刷新資料
const handleRefresh = async () => {
await mutate();
};

5. 搭配條件式載入

const shouldFetch = userId !== null;

const { data } = useSWR(shouldFetch ? `/api/users/${userId}` : null, fetcher);

6. 自訂快取與設定

import useSWR from 'swr';

const { data, error } = useSWR('/api/data', fetcher, {
refreshInterval: 10000, // 每 10 秒重新抓資料
revalidateOnFocus: true, // 回到畫面時自動刷新
dedupingInterval: 5000, // 阻止過於頻繁的 API 請求
});

總結

SWR 提供了一種優雅、聲明式的方式來管理 React 應用中的資料請求與快取,不僅能有效簡化程式碼,還能提高使用者體驗與應用效能。其彈性與擴充性也適合應用於中大型專案中。

當我們熟悉了 SWR 的基本用法後,接下來也可以進一步探索以下功能:

  • Mutation API:用於資料寫入後手動更新快取。
  • 依賴 key 的動態載入:搭配 router 參數動態請求資料。
  • 全域快取策略自訂(SWRConfig):統一設定所有請求的行為。

透過 SWR,我們不再需要手動處理快取與副作用邏輯,只需專注於資料的呈現與邏輯本身,是開發現代 React 應用的絕佳利器。

參考文件

  1. React Hooks for Data Fetching

HTML & CSS 切版入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

HTML(HyperText Markup Language)是網頁的基礎結構,透過標籤(Tag)定義不同的內容與結構。

1.1 常見標籤

  • <!DOCTYPE html>:宣告 HTML 文件類型。
  • <html>:HTML 文件的根標籤。
  • <head>:包含頁面設定、SEO 資訊、CSS 連結等。
  • <title>:設定網頁標題。
  • <body>:放置頁面可見內容。
  • <h1> ~ <h6>:標題。
  • <p>:段落。
  • <a>:超連結。
  • <img>:圖片。
  • <ul><ol><li>:無序與有序列表。
  • <div>:區塊。
  • <span>:行內元素。
  • <table><tr><td>:表格。

1.2 HTML5 新增語意標籤

  • <header>:頁首。
  • <nav>:導航。
  • <section>:區段。
  • <article>:獨立內容。
  • <aside>:側邊欄。
  • <footer>:頁尾。

2. CSS 基礎概念

CSS(Cascading Style Sheets)用於設計與美化 HTML 元素。

2.1 CSS 引入方式

  • 內嵌樣式(Inline Style):直接寫在 HTML 標籤內,例如:
    <p style="color: red; font-size: 16px;">這是一段文字</p>
  • 內部樣式(Internal Style):寫在 <style> 標籤內,例如:
    <style>
    p { color: blue; font-size: 18px; }
    </style>
  • 外部樣式(External Style):將 CSS 放入 .css 文件中,再用 <link> 連結,例如:
    <link rel="stylesheet" href="styles.css">

2.2 CSS 選擇器

  • 標籤選擇器:影響所有相同標籤,例如:
    p { color: green; }
  • 類別選擇器(Class):適用於多個元素,例如:
    .box { background-color: yellow; }
    <div class="box">內容</div>
  • ID 選擇器:適用於單一元素,例如:
    #header { font-size: 24px; }
    <h1 id="header">標題</h1>
  • 後代選擇器:選擇特定層級內的元素,例如:
    div p { color: blue; }

2.3 盒模型(Box Model)

盒模型包含四個部分:

  1. Content(內容區域)。
  2. Padding(內距,內容與邊框之間的距離)。
  3. Border(邊框)。
  4. Margin(外距,與其他元素的距離)。

範例:

.box {
width: 200px;
height: 100px;
padding: 20px;
border: 2px solid black;
margin: 10px;
}

3. 常見版型切版技巧

3.1 Flexbox 佈局

Flexbox 用於彈性排列子元素。

.container {
display: flex;
justify-content: space-between;
align-items: center;
}

3.2 Grid 佈局

Grid 提供更強大的網格系統。

.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}

3.3 響應式設計(RWD)

使用 @media 來適應不同螢幕尺寸。

@media (max-width: 768px) {
.container {
flex-direction: column;
}
}

4. 實戰案例:基本網頁切版

HTML

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>簡單網頁</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>我的網站</h1>
</header>
<nav>
<ul>
<li><a href="#">首頁</a></li>
<li><a href="#">關於</a></li>
<li><a href="#">聯絡</a></li>
</ul>
</nav>
<section class="content">
<p>這是一個簡單的 HTML & CSS 切版示範。</p>
</section>
</body>
</html>

CSS

body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
header {
background: #333;
color: white;
text-align: center;
padding: 10px;
}
nav ul {
list-style: none;
display: flex;
justify-content: center;
padding: 0;
}
nav ul li {
margin: 0 15px;
}
nav a {
text-decoration: none;
color: black;
}
.content {
max-width: 800px;
margin: auto;
padding: 20px;
}

5. 總結

透過學習 HTML 與 CSS,可以建立結構清晰、外觀美觀的網頁。建議多加練習不同的切版方式,如 Flexbox 和 Grid,並運用 RWD 技巧來提升適應性,讓網站在不同裝置上都能有良好的呈現效果。

CSS transition 入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

CSS transition 屬性允許元素在狀態變化時產生平滑的動畫效果,使 UI 更加流暢和自然。這項技術通常應用於按鈕、圖片、卡片等 UI 元素的互動效果,如懸停、點擊或狀態變更。

1. transition 基礎概念

CSS transition 屬性用於定義當元素的某些 CSS 屬性發生變化時,該變化應如何逐漸呈現,而非立即改變。基本語法如下:

transition: property duration timing-function delay;
  • property:指定要應用過渡效果的 CSS 屬性。
  • duration:設定過渡動畫的時間(如 0.5s200ms)。
  • timing-function:定義動畫的速度曲線(如 easelinear)。
  • delay:動畫開始前的延遲時間(可選,默認為 0s)。

2. transition 常見應用

2.1 過渡單一屬性

.button {
background-color: blue;
color: white;
padding: 10px 20px;
border-radius: 5px;
transition: background-color 0.3s ease;
}

.button:hover {
background-color: darkblue;
}

當滑鼠懸停在 .button 上時,背景顏色將在 0.3s 內從 blue 變為 darkblue

2.2 過渡多個屬性

.card {
width: 200px;
height: 300px;
background-color: lightgray;
transform: scale(1);
transition: background-color 0.3s ease, transform 0.5s ease-in-out;
}

.card:hover {
background-color: gray;
transform: scale(1.1);
}

當滑鼠懸停時,.card 的背景顏色會變深,並且整個卡片會放大 1.1 倍。

3. transition 進階應用

3.1 transition-timing-function(動畫速度曲線)

timing-function 用於定義動畫的速度變化方式,常見的值如下:

  • linear:等速變化。
  • ease(預設值):開始與結束較慢,中間較快。
  • ease-in:開始較慢,之後加速。
  • ease-out:開始較快,最後減速。
  • ease-in-out:開始和結束都較慢。

範例:

.box {
width: 100px;
height: 100px;
background-color: red;
transition: transform 1s ease-in-out;
}

.box:hover {
transform: translateX(200px);
}

當滑鼠懸停時,.box 會平滑地向右移動 200px,並且動畫在開始和結束時較慢。

3.2 transition-delay(延遲時間)

可以設定 transition-delay 來延遲動畫的開始時間。

.box {
width: 100px;
height: 100px;
background-color: green;
transition: background-color 0.5s ease-in 1s;
}

.box:hover {
background-color: darkgreen;
}

當滑鼠懸停時,background-color 會延遲 1s 後才開始變化。

4. transition 實際應用範例

4.1 按鈕的點擊效果

.button {
padding: 12px 24px;
background-color: #ff5733;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: transform 0.2s ease-out;
}

.button:active {
transform: scale(0.95);
}

當按下 .button 時,按鈕會稍微縮小,產生按壓感。

4.2 漸變顯示效果

.fade-box {
width: 100px;
height: 100px;
background-color: blue;
opacity: 0;
transition: opacity 1s ease-in-out;
}

.fade-box.show {
opacity: 1;
}

.show 類別被添加時,.fade-box 會在 1s 內逐漸顯示。

4.3 圖片放大效果

.image-container img {
width: 100px;
transition: width 0.3s ease-in-out;
}

.image-container:hover img {
width: 150px;
}

當滑鼠懸停時,圖片會平滑地放大。

5. transition vs animation

雖然 transitionanimation 都能用來製作動畫,但它們的用途不同:

  • transition:適合用於元素的狀態變更(如 hoverfocus)。
  • animation:適用於更複雜的動畫,如連續循環的動畫。

如果需要更高級的動畫,例如無限重複、按時間順序變化的動畫,則應使用 @keyframesanimation

6. 總結

CSS transition 是製作動畫效果最簡單且高效的方法之一。透過 transition,可以讓 UI 更加生動,使使用者體驗更流暢。掌握 transition 的基本語法與進階應用後,可以靈活運用於各種互動效果,如按鈕動畫、圖片過渡、淡入淡出等,讓網頁更加吸引人。

CSS transform 入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

CSS transform 屬性是一個強大的工具,可以用來對 HTML 元素進行旋轉、縮放、移動及傾斜等變換,而不會影響其他元素的佈局。這使得 transform 非常適合用來建立動畫效果、視覺調整以及 UI 微調。

1. transform 基礎概念

transform 屬性可以接受一個或多個變換函數,使元素在不影響文檔流的情況下進行變換。這些變換主要包含:

  • 平移 (translate)
  • 縮放 (scale)
  • 旋轉 (rotate)
  • 傾斜 (skew)
  • 矩陣變換 (matrix)

2. transform 常見屬性

2.1 平移 (translate)

translate(x, y) 用於移動元素的 X 軸與 Y 軸位置。

.box {
transform: translate(50px, 100px);
}

此範例將 .box 元素向右移動 50px,向下移動 100px。

單軸平移

  • translateX(50px):僅在 X 軸移動 50px。
  • translateY(100px):僅在 Y 軸移動 100px。

2.2 縮放 (scale)

scale(x, y) 用於縮放元素。

.box {
transform: scale(1.5, 0.5);
}

此範例將 .box 元素的寬度放大 1.5 倍,高度縮小為原來的一半。

單軸縮放

  • scaleX(2):寬度變為 2 倍。
  • scaleY(0.5):高度變為 0.5 倍。

2.3 旋轉 (rotate)

rotate(angle) 用於旋轉元素。

.box {
transform: rotate(45deg);
}

此範例將 .box 元素順時針旋轉 45 度。

2.4 傾斜 (skew)

skew(x-angle, y-angle) 用於使元素傾斜。

.box {
transform: skew(30deg, 10deg);
}

此範例將 .box 在 X 軸方向傾斜 30 度,在 Y 軸方向傾斜 10 度。

單軸傾斜

  • skewX(15deg):僅在 X 軸傾斜 15 度。
  • skewY(25deg):僅在 Y 軸傾斜 25 度。

2.5 矩陣變換 (matrix)

matrix(a, b, c, d, e, f) 是一個綜合性變換函數,允許透過 6 個參數來同時應用縮放、旋轉、傾斜與位移。

.box {
transform: matrix(1, 0.5, 0.5, 1, 50, 100);
}

這樣的矩陣表示:

  • 1:X 軸縮放。
  • 0.5:X 軸傾斜。
  • 0.5:Y 軸傾斜。
  • 1:Y 軸縮放。
  • 50:X 軸位移。
  • 100:Y 軸位移。

3. transform 的應用範例

3.1 建立簡單的 hover 效果

利用 transform,可以輕鬆製作滑鼠懸停的動畫效果,例如按鈕放大效果:

.button {
display: inline-block;
padding: 10px 20px;
background-color: #3498db;
color: white;
text-align: center;
border-radius: 5px;
transition: transform 0.3s ease-in-out;
}

.button:hover {
transform: scale(1.1);
}

3.2 圖片翻轉效果

使用 rotateY(180deg) 來製作翻轉效果,常用於卡片翻轉動畫。

.card {
width: 200px;
height: 300px;
background-color: lightgray;
transform: rotateY(0deg);
transition: transform 0.5s;
}

.card:hover {
transform: rotateY(180deg);
}

3.3 旋轉動畫

結合 @keyframestransform,可以製作無限旋轉動畫。

@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

.spinner {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: red;
animation: spin 2s linear infinite;
}

4. transform-origin 的應用

transform-origin 屬性用於指定變換的基準點,預設值為 50% 50%(元素中心)。

.box {
transform-origin: top left;
transform: rotate(45deg);
}

此範例中,元素將以左上角為旋轉點,而非默認的中心點。

5. perspective 與 3D 變換

當使用 3D 變換(如 rotateXrotateY)時,可使用 perspective 來模擬景深效果。

.container {
perspective: 500px;
}

.box {
transform: rotateY(45deg);
}

此範例讓 .box 具有 3D 透視效果,使其看起來更真實。

6. 總結

CSS transform 是一個靈活且強大的屬性,可以用來製作動畫、視覺調整及增強 UI 體驗。透過 translatescalerotateskew 等函數,你可以輕鬆地操控元素的外觀,讓你的網頁更具吸引力。

HTML 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

1. 什麼是 HTML?

HTML(HyperText Markup Language,超文本標記語言)是建立網頁的標準語言。它用標籤(tags)來結構化內容,讓瀏覽器能夠解析並顯示網頁。HTML 主要負責網頁的結構,而樣式與行為則交由 CSS 和 JavaScript 負責。


2. HTML 文件基本結構

一個基本的 HTML 文件包含以下部分:

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的第一個 HTML 頁面</title>
</head>
<body>
<h1>歡迎來到我的網站</h1>
<p>這是一個簡單的 HTML 頁面。</p>
</body>
</html>
  • <!DOCTYPE html>:宣告 HTML5 文件類型。
  • <html lang="zh-TW">:定義 HTML 根標籤,lang="zh-TW" 表示使用繁體中文。
  • <head>:包含頁面的元資訊(meta information),如編碼、標題等。
  • <meta charset="UTF-8">:設定網頁使用 UTF-8 編碼,確保中文字元正確顯示。
  • <meta name="viewport" content="width=device-width, initial-scale=1.0">:讓網頁適應不同裝置的螢幕大小。
  • <title>:設定瀏覽器標籤上的標題。
  • <body>:放置網頁的主要內容,如標題、段落、圖片等。

3. 常見 HTML 標籤

3.1 標題與段落

HTML 提供六種標題 (<h1><h6>),以及 <p> 用來表示段落。

<h1>這是主標題</h1>
<h2>這是次標題</h2>
<h3>這是小標題</h3>
<p>這是一段文字,HTML 會自動換行。</p>
3.2 超連結

使用 <a> 標籤建立超連結:

<a href="https://www.google.com" target="_blank">前往 Google</a>
  • href 指定連結網址。
  • target="_blank" 讓連結在新視窗開啟。
3.3 圖片

使用 <img> 來插入圖片:

<img src="image.jpg" alt="示範圖片" width="300">
  • src 指定圖片來源。
  • alt 提供替代文字。
  • width 設定圖片寬度(可用 height 指定高度)。
3.4 清單

有序清單 (<ol>) 和無序清單 (<ul>):

<h2>購物清單</h2>
<ul>
<li>蘋果</li>
<li>香蕉</li>
<li>橘子</li>
</ul>

<h2>步驟</h2>
<ol>
<li>打開電腦</li>
<li>開啟瀏覽器</li>
<li>輸入網址</li>
</ol>
3.5 表格

使用 <table> 來建立表格,並搭配 <tr>(表格列)、<th>(表頭)、<td>(儲存格):

<table border="1">
<tr>
<th>姓名</th>
<th>年齡</th>
</tr>
<tr>
<td>小明</td>
<td>25</td>
</tr>
<tr>
<td>小華</td>
<td>30</td>
</tr>
</table>
  • border="1" 設定表格邊框。
3.6 表單

使用 <form> 來建立表單:

<form action="submit.php" method="post">
<label for="name">姓名:</label>
<input type="text" id="name" name="name" required>
<br>
<label for="email">電子郵件:</label>
<input type="email" id="email" name="email" required>
<br>
<input type="submit" value="提交">
</form>
  • action="submit.php" 指定表單提交到 submit.php
  • method="post" 指定使用 POST 方法傳遞數據。
  • required 讓輸入欄位變成必填。

4. HTML5 新增標籤

HTML5 引入了一些語義化標籤,使網頁更具結構性。

<header>
<h1>網站標題</h1>
</header>
<nav>
<ul>
<li><a href="#">首頁</a></li>
<li><a href="#">關於我們</a></li>
<li><a href="#">聯絡我們</a></li>
</ul>
</nav>
<section>
<h2>最新消息</h2>
<p>這是一則最新消息的內容。</p>
</section>
<footer>
<p>版權所有 &copy; 2025</p>
</footer>
  • <header>:頁首。
  • <nav>:導覽區塊。
  • <section>:內容區塊。
  • <footer>:頁尾資訊。

5. HTML 與 CSS 結合

雖然 HTML 定義了結構,但我們通常使用 CSS 來美化頁面。內嵌 CSS 可以寫在 <style> 內:

<style>
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
text-align: center;
}
h1 {
color: #007bff;
}
p {
font-size: 18px;
}
</style>

或者外部引入 CSS 檔案:

<link rel="stylesheet" href="styles.css">

6. 總結

這篇教學筆記介紹了 HTML 的基本語法,包括標籤、結構與常見元素。學會這些後,可以進一步學習 CSS 來美化網頁,或是學習 JavaScript 增強互動性。最好的學習方式是透過實際練習與製作小專案來熟悉 HTML 語法。

Python Decorator 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在 Python 的日常開發中,decorator(裝飾器) 是一個非常強大的語法工具,常用於增強函式功能,例如:記錄日誌、驗證權限、計時、快取等。在許多框架(如 Flask、Django)或第三方函式庫中,也可以經常看到裝飾器的身影。

然而對初學者來說,decorator 的語法可能一開始比較難以理解,尤其涉及到函式是「第一類物件(first-class object)」、「閉包(closure)」的概念。本篇筆記將循序漸進帶你理解 decorator 的本質與應用方式。


重點摘要

  • Python 函式是第一類物件:可以作為參數傳遞、作為回傳值、賦值給變數。
  • 閉包(Closure):內部函式可以存取外部函式的變數,函式結束後變數仍可存活。
  • Decorator 是一種語法糖,本質是「接收一個函式,回傳一個新的函式」的高階函式。
  • 使用 @ 語法糖可以簡潔地套用裝飾器
  • 裝飾器可用於邏輯共用、權限驗證、效能監控、快取等實務情境
  • functools.wraps 可保持被裝飾函式的名稱與 docstring 資訊

一、基礎概念與語法

1. 函式是物件

def greet(name):
return f"Hello, {name}"

say_hello = greet
print(say_hello("Alice")) # Hello, Alice

函式可以被賦值給變數、作為參數傳遞,也能作為回傳值。


2. 函式作為參數的例子

def do_twice(func):
def wrapper():
func()
func()
return wrapper

def say_hi():
print("Hi!")

do_twice(say_hi)()

這就是簡單的裝飾器雛形,do_twice 接收一個函式,回傳一個新的函式。


二、實作一個簡單 decorator

1. 不帶參數的 decorator

def my_decorator(func):
def wrapper():
print("執行前")
func()
print("執行後")
return wrapper

@my_decorator
def say_hello():
print("Hello!")

say_hello()

輸出:

執行前
Hello!
執行後

@my_decorator 這行等同於 say_hello = my_decorator(say_hello)。裝飾器會接手原本的函式,包裝成新的邏輯後回傳。


2. 處理有參數的函式

def my_decorator(func):
def wrapper(*args, **kwargs):
print("執行前")
result = func(*args, **kwargs)
print("執行後")
return result
return wrapper

@my_decorator
def greet(name):
print(f"Hello, {name}")

greet("KD")

使用 *args, **kwargs 可以支援任何參數的函式。


3. 保留原函式資訊:使用 functools.wraps

import functools

def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("執行前")
return func(*args, **kwargs)
return wrapper

@my_decorator
def add(x, y):
"""加總兩數"""
return x + y

print(add.__name__) # add
print(add.__doc__) # 加總兩數

沒有 functools.wraps,函式的名稱會變成 wrapper,容易影響除錯與文件產生。


三、實用範例:計時 decorator

import time
import functools

def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 執行時間:{end - start:.4f} 秒")
return result
return wrapper

@timer
def slow_function():
time.sleep(1.5)
print("完成耗時操作")

slow_function()

四、進階:帶參數的 decorator

有時我們希望 decorator 接收參數,例如指定權限等,這時候會需要再多一層函式包裝:

def repeat(times):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator

@repeat(3)
def say_hello():
print("Hello!")

say_hello()

repeat(3) 會先執行,回傳 decorator(func),再包裝原函式。


五、常見應用場景

  • 日誌紀錄(logging)
  • 權限驗證(authorization)
  • 執行時間分析(performance monitoring)
  • 快取(caching)
  • API 路由(如 Flask 的 @app.route)

總結

Python 的 decorator 是一個非常實用的語法技巧,一旦理解其本質為「函式的包裝器」,就可以在實務開發中靈活應用。它讓我們可以以簡潔的方式注入共用邏輯,大大提升程式的可讀性與可維護性。

我們在練習 decorator 時,建議搭配日常開發情境,如記錄日誌、印出函式執行時間,從實作中加深理解。當你越熟悉它,便越能體會其在 Python 世界中的威力。