跳到主要內容

Web Day 3 HTTP 與 REST:API 設計的原則

Web Day 3 HTTP 與 REST:API 設計的原則

執行需求:CPU 可跑。在昨天把環境建好之後,今天要進入後端最根本的觀念:HTTP 與 REST。你會學到 HTTP 方法與狀態碼怎麼選、URL 與資源怎麼命名、為什麼 REST 成為業界主流的 API 風格,最後把昨天的 hello-api 範例改寫成更符合 REST 慣例的版本。這些觀念會貫穿整個系列,每一天的 FastAPI 程式都會用到。

引言

寫後端程式的人很容易陷入一個誤區:「反正伺服器能回應就好」。如果只是自己測試的小程式,這個說法沒錯;但只要 API 要給別人(前端工程師、手機 App、合作廠商)呼叫,「能回應」就遠遠不夠。我們需要的是「讓別人一看 URL 就知道這個 API 在做什麼」、「讓別人一看狀態碼就知道請求成功或失敗」、「讓別人一看錯誤訊息就知道該怎麼修正」。這整套紀律,就是 HTTP 與 REST 要幫你解決的事。

HTTP 是網際網路上最普及的請求-回應協定,從 1991 年的 HTTP/0.9 一路到 2022 年推出的 HTTP/3,已經三十多年歷史。REST(Representational State Transfer)則是 Roy Fielding 在 2000 年博士論文中提出的一種架構風格,不是協定也不是標準,而是一組「怎麼用 HTTP 才合理」的設計原則。這兩個東西搭配起來,就形成現代 Web API 的主流寫法。

這篇文章會做四件事:第一,解釋 HTTP 請求與回應的結構;第二,介紹 HTTP 方法與狀態碼;第三,整理 REST 風格的設計原則(資源命名、統一介面、無狀態);第四,用 FastAPI 示範怎麼把昨天的範例改寫得更 RESTful。今天不寫複雜的應用,重點是把觀念弄清楚。

HTTP 通訊協定基礎

HTTP 是「超文字傳輸協定」(HyperText Transfer Protocol)的縮寫,運作模式非常簡單:呼叫端送出一段「請求」(request),伺服器回應一段「回應」(response)。整個交換過程是無狀態的(stateless)——意思是伺服器不會記得「上一個請求是誰送來的」,每個請求都是獨立的。

無狀態聽起來像缺點,其實是特性。它讓 HTTP 極度容易擴展:你可以隨時把請求送到任何一台伺服器(伺服器之間不需要共享呼叫端的狀態),伺服器之間不需要共享狀態(共享狀態改用資料庫、快取或外部儲存)。現代大型網站能撐住幾百萬使用者,就是靠這個特性。

一個 HTTP 請求由三部分組成:

  • 請求行(request line):包含 HTTP 方法、路徑、HTTP 版本,例如 GET /api/items HTTP/1.1。
  • 標頭(headers):零到多行的鍵值對,例如 Host、Content-Type、Authorization。
  • 主體(body):選填,承載要送往伺服器的資料(JSON、表單、檔案等)。

回應也是三部分:狀態列(HTTP 版本、狀態碼、原因短語)、標頭、主體。我們用一支簡單的 Python 程式把這件事看清楚:

# demo_http.py
# 用 httpx 打 hello-api 的根端點,把請求與回應結構印出來
import httpx

# 啟動 hello-api 範例(uvicorn hello_api.main:app --reload --port 8000)

request = httpx.Request("GET", "http://127.0.0.1:8000/")
print("=== 請求 ===")
print(f"方法與路徑:{request.method} {request.url.path}")
print(f"HTTP 版本:HTTP/1.1(httpx 預設;HTTP/2 需另開選項)")
print(f"標頭:{dict(request.headers)}")
# 輸出(節錄):
#   方法與路徑:GET /
#   HTTP 版本:HTTP/1.1
#   標頭:{'host': '127.0.0.1:8000', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'user-agent': 'python-httpx/0.28.x', 'connection': 'keep-alive'}

response = httpx.get("http://127.0.0.1:8000/")
print()
print("=== 回應 ===")
print(f"狀態碼:{response.status_code} {response.reason_phrase}")
print(f"標頭:{dict(response.headers)}")
print(f"主體:{response.text}")
# 輸出(節錄):
#   狀態碼:200 OK
#   標頭:{'content-length': '...', 'content-type': 'application/json', 'date': '...', 'server': 'uvicorn'}
#   主體:{"message":"Hello, FastAPI!","service":"hello-api"}

這個小段把 HTTP 通訊的兩端都攤開來。注意 content-type: application/json 這個標頭——它告訴呼叫端「我回給你的是 JSON 格式,請用 JSON parser 解析」。這類內容協商(content negotiation)的機制,讓同一個 URL 理論上可以回應不同格式(例如 HTML、JSON、XML),只要呼叫端在請求標頭宣告自己要的格式即可。實務上現代 API 幾乎都是 JSON 格式,所以這個協商機制很少被用到,但理解它的存在有助於讀懂規格書。

另一個值得注意的細節:User-Agent 標頭會帶上函式庫與版本(這裡是 python-httpx/0.28.x)。伺服器可以根據這個標頭判斷呼叫端類型、限制某些舊版呼叫端的存取、或蒐集統計資料。我們在 Day 32 會看到如何在 CI/CD 裡用這個標頭做環境識別。

HTTP 方法:CRUD 與語意

HTTP 定義了九種方法(method),但實務上九成以上的 API 只會用到五種:

方法 語意 是否安全(safe) 是否等冪(idempotent)
GET 讀取資源 是 是
POST 建立資源或觸發動作 否 否
PUT 替換整個資源 否 是
PATCH 部分更新資源 否 否(一般來說)
DELETE 刪除資源 否 是

「安全」指的是呼叫後伺服器狀態不變(純讀取);「等冪」指的是重複呼叫同樣的請求,結果一樣。例如刪除同一筆資源兩次:第一次回 204 No Content、第二次回 404 Not Found,從「資源是否存在」的角度看結果是一致的(資源不存在),所以它是等冪。建立一筆資源兩次會得到兩筆,這就是不等冪,所以 POST 不等冪。

理解「等冪」對除錯非常重要。當使用者說「我按了兩次按鈕,結果被建立兩筆」時,問題通常在於前端在 POST 之前沒有 disable 按鈕、或是後端沒有對 POST 做去重(idempotency key)。Day 10 處理錯誤時會示範這個議題。

HTTP 狀態碼:成功與失敗的標準語言

狀態碼(status code)是伺服器告訴呼叫端「結果如何」的標準化方式。第一位數代表大類:

類別 意義 常見狀態碼
1xx 資訊 100 Continue(少用)
2xx 成功 200 OK、201 Created、204 No Content
3xx 重新導向 301 Moved Permanently、304 Not Modified、307 Temporary Redirect
4xx 呼叫端錯誤 400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found、422 Unprocessable Entity
5xx 伺服器錯誤 500 Internal Server Error、502 Bad Gateway、503 Service Unavailable

實務上有幾個最容易用錯的狀態碼:

  • 200 vs 201 vs 204:GET 成功用 200;POST 建立資源成功用 201,且常在標頭 Location 給出新資源的 URL;PUT/PATCH/DELETE 成功且無主體回傳時用 204。
  • 400 vs 422:400 是「請求格式錯了(例如 JSON 解析失敗)」;422(FastAPI/Pydantic 預設)是「請求格式對了,但內容驗證失敗(例如 email 格式不對)」。
  • 401 vs 403:401 是「你沒帶 token 或 token 過期」;403 是「你有身份,但這個資源不允許你存取」。兩者常被混用,理解差異對做認證很重要(Day 12 會示範)。

把昨天的 hello-api 擴充一下,加上錯誤路徑示範狀態碼的差異:

# src/hello_api/main.py
# 加入錯誤示範端點
from fastapi import FastAPI, HTTPException

app = FastAPI(title="hello-api", version="0.2.0")

ITEMS = {
    1: {"id": 1, "name": "Notebook", "price": 120},
    2: {"id": 2, "name": "Pen", "price": 25},
}


@app.get("/items/{item_id}")
def read_item(item_id: int):
    item = ITEMS.get(item_id)
    if item is None:
        # 找不到資源:404
        raise HTTPException(status_code=404, detail="找不到這個資源")
    return item


@app.get("/items-bad")
def read_items_bad():
    # 伺服器內部錯誤:500
    raise RuntimeError("故意的,示範 500")
# FastAPI 會把 RuntimeError 轉成 500 Internal Server Error

這段示範兩個常見的狀態碼:用 HTTPException(status_code=404) 主動告訴呼叫端「這個資源不存在」;故意觸發的 RuntimeError 則會被 FastAPI 攔截並回應 500。實務上 500 通常代表程式有 bug,應該在記錄伺服器端日誌(Day 22)後儘快修復;不應該在正常邏輯裡故意丟 500。

REST 風格的設計原則

REST 不是標準,而是一組設計原則。Roy Fielding 在 2000 年提出時列出六個約束,但實務上後端工程師關心的通常只有三個:

  • 資源導向:URL 代表「資源」(resource),不是「動作」。所以 URL 用名詞(/items、/users),不用動詞(/getItems、/createUser)。
  • 統一介面:用 HTTP 方法表達動作(GET 讀取、POST 建立、PUT/PATCH 更新、DELETE 刪除)。同一個 URL 接受不同方法就有不同行為。
  • 無狀態:每個請求都帶足夠資訊讓伺服器處理,不依賴伺服器端的 session。需要 session 的情境改用 token(Day 12)。

把昨天的 hello-api 改寫成 RESTful 版本:

# src/hello_api/main.py
# REST 風格的 hello-api 範例
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field

app = FastAPI(title="hello-api", version="0.3.0")


class Item(BaseModel):
    # 回應用的資料模型
    id: int
    name: str = Field(min_length=1, max_length=80)
    price: int = Field(ge=0)  # price >= 0


class ItemCreate(BaseModel):
    # 建立用的請求模型(沒有 id,由伺服器產生)
    name: str = Field(min_length=1, max_length=80)
    price: int = Field(ge=0)


# 假資料(Day 6 會換成 SQLite)
_items: dict[int, Item] = {
    1: Item(id=1, name="Notebook", price=120),
    2: Item(id=2, name="Pen", price=25),
}
_next_id = 3


@app.get("/items")
def list_items():
    # 讀取資源集合
    return list(_items.values())


@app.get("/items/{item_id}")
def read_item(item_id: int):
    # 讀取單一資源
    item = _items.get(item_id)
    if item is None:
        raise HTTPException(status_code=404, detail="item not found")
    return item


@app.post("/items", status_code=201)
def create_item(payload: ItemCreate):
    # 建立新資源
    global _next_id
    new = Item(id=_next_id, **payload.model_dump())
    _items[_next_id] = new
    _next_id += 1
    return new


@app.put("/items/{item_id}")
def replace_item(item_id: int, payload: ItemCreate):
    # 完整替換資源
    if item_id not in _items:
        raise HTTPException(status_code=404, detail="item not found")
    replaced = Item(id=item_id, **payload.model_dump())
    _items[item_id] = replaced
    return replaced


@app.patch("/items/{item_id}")
def update_item(item_id: int, payload: dict):
    # 部分更新資源
    item = _items.get(item_id)
    if item is None:
        raise HTTPException(status_code=404, detail="item not found")
    data = item.model_dump()
    data.update(payload)
    updated = Item(**data)
    _items[item_id] = updated
    return updated


@app.delete("/items/{item_id}", status_code=204)
def delete_item(item_id: int):
    # 刪除資源,回 204 無主體
    if item_id not in _items:
        raise HTTPException(status_code=404, detail="item not found")
    del _items[item_id]
    return None

這個版本完整展現 REST 慣例:URL /items 是資源集合、/items/{id} 是單一資源;GET 讀取、POST 建立(201)、PUT 完整替換、PATCH 部分更新、DELETE 刪除(204)。Pydantic 模型負責驗證請求內容,FastAPI 會自動把驗證失敗轉成 422 錯誤。

完整實作:用 httpx 走完整個 REST 迴圈

啟動 hello-api(記得 uv run uvicorn hello_api.main:app --reload --port 8000),然後用下面這支腳本走完整個 CRUD:

# tests/test_rest_cycle.py
# 完整走一次 REST CRUD,確認狀態
import httpx

BASE = "http://127.0.0.1:8000"


def main():
    with httpx.Client(base_url=BASE, timeout=5.0) as client:
        # 1. 讀取資源集合
        r = client.get("/items")
        print(f"GET /items -> {r.status_code}", r.json())
        # 輸出(範例):GET /items -> 200 [{'id': 1, ...}, {'id': 2, ...}]

        # 2. 讀取單一資源
        r = client.get("/items/1")
        print(f"GET /items/1 -> {r.status_code}", r.json())
        # 輸出(範例):GET /items/1 -> 200 {'id': 1, 'name': 'Notebook', 'price': 120}

        # 3. 建立新資源
        new_item = {"name": "Mug", "price": 180}
        r = client.post("/items", json=new_item)
        print(f"POST /items -> {r.status_code}", r.json())
        # 輸出(範例):POST /items -> 201 {'id': 3, 'name': 'Mug', 'price': 180}
        created_id = r.json()["id"]

        # 4. 部分更新資源
        r = client.patch(f"/items/{created_id}", json={"price": 200})
        print(f"PATCH /items/{created_id} -> {r.status_code}", r.json())
        # 輸出(範例):PATCH /items/3 -> 200 {'id': 3, 'name': 'Mug', 'price': 200}

        # 5. 完整替換資源
        r = client.put(f"/items/{created_id}", json={"name": "Cup", "price": 220})
        print(f"PUT /items/{created_id} -> {r.status_code}", r.json())
        # 輸出(範例):PUT /items/3 -> 200 {'id': 3, 'name': 'Cup', 'price': 220}

        # 6. 刪除資源
        r = client.delete(f"/items/{created_id}")
        print(f"DELETE /items/{created_id} -> {r.status_code}")
        # 輸出(範例):DELETE /items/3 -> 204

        # 7. 再次讀取(確認真的刪掉了)
        r = client.get(f"/items/{created_id}")
        print(f"GET /items/{created_id} -> {r.status_code}", r.json())
        # 輸出(範例):GET /items/3 -> 404 {'detail': 'item not found'}


main()

這個迴圈把 POST/PATCH/PUT/DELETE 與狀態碼(201/200/204/404)一次展示。實務上 PATCH 的輸入通常會用另一個 Pydantic 模型(部分欄位都變 optional)來嚴格驗證,這裡為了簡化用 dict 收;Day 5 會深入探討請求驗證的細節。

驗證請求體格式錯誤會怎樣:

# 用 curl 試一個故意壞掉的請求
curl -s -X POST http://127.0.0.1:8000/items \
    -H "Content-Type: application/json" \
    -d '{"name": "", "price": -1}' | python -m json.tool
# 輸出(節錄):
# {
#     "detail": [
#         {
#             "type": "string_too_short",
#             "loc": ["body", "name"],
#             "msg": "String should have at least 1 character",
#             "input": ""
#         },
#         {
#             "type": "less_than_equal",
#             "loc": ["body", "price"],
#             "msg": "Input should be greater than or equal to 0",
#             "input": -1
#         }
#     ]
# }
# HTTP 狀態碼:422

這段範例展現了 FastAPI/Pydantic 的強大:當請求不符合 ItemCreate 模型的約束時,伺服器會回 422 並列出每一個欄位的錯誤訊息(哪個欄位、為什麼錯、實際輸入是什麼)。前端可以直接拿這份結構化的錯誤回應做表單驗證,省下自己寫一堆檢查的功夫。

常見錯誤與踩雷

第一個常見的踩雷是「動詞型 URL」。例如 /getItems、/createUser、/deleteOrder/1001 這些寫法是 RPC(Remote Procedure Call)風格,不是 REST。問題在於動詞型 URL 必須對到特定方法,無法用 HTTP 方法區分動作;改用 /items + GET/POST/PUT/DELETE 組合,未來想加 cache header、批次操作、權限控管都更彈性。

第二個是「狀態碼用 200 包一切錯誤」。某些 API 會回 {"code": 404, "message": "..."} 但 HTTP 狀態碼仍然是 200。這違背了 HTTP 的設計意圖:呼叫端程式庫(如 httpx、瀏覽器 fetch)會根據 HTTP 狀態碼決定怎麼處理(重試、丟例外、顯示錯誤頁)。混用 200 + 自訂錯誤碼會讓這些自動化機制失靈。請一律用正確的 HTTP 狀態碼。

第三個是「GET 卻改變伺服器狀態」。例如「GET /user/clear-cache」會清掉使用者快取——這違背了 GET 應該是「安全」的語意。除錯或監控時偶爾會這樣設計,但千萬不要在正式 API 用 GET 來刪除或修改資料,否則瀏覽器預讀、爬蟲、CDN 快取都可能誤觸。

進階範例:用 Python 模擬 REST 客戶端

理解 REST 的最佳方式之一是「自己當客戶端」。前面用 httpx 走完整個 CRUD,這裡再展示一個更完整的「通用 API 客戶端」設計:把所有 REST 慣用語義包進一個 helper class,未來你自己的前端或 SDK 都能用同一套介面。

# rest_client.py
# 一個極簡的 REST 客戶端,封裝 GET/POST/PUT/PATCH/DELETE
from typing import Any

import httpx


class RestClient:
    """包裝基本 CRUD 操作的客戶端"""

    def __init__(self, base_url: str, headers: dict[str, str] | None = None):
        self._client = httpx.Client(
            base_url=base_url,
            timeout=10.0,
            headers=headers or {},
        )

    def get(self, path: str, **kwargs) -> httpx.Response:
        return self._client.get(path, **kwargs)

    def post(self, path: str, json: dict[str, Any] | None = None) -> httpx.Response:
        return self._client.post(path, json=json)

    def put(self, path: str, json: dict[str, Any] | None = None) -> httpx.Response:
        return self._client.put(path, json=json)

    def patch(self, path: str, json: dict[str, Any] | None = None) -> httpx.Response:
        return self._client.patch(path, json=json)

    def delete(self, path: str) -> httpx.Response:
        return self._client.delete(path)

    def close(self):
        self._client.close()


# 用法
client = RestClient("http://127.0.0.1:8000")
r = client.get("/items/1")
print(f"GET /items/1 -> {r.status_code}", r.json())
client.close()

這支 RestClient 把所有 HTTP 方法封裝好,未來你在寫前端或 SDK 時可以省下一些樣板程式碼。它的設計哲學是「一個動詞對應一個方法」,跟 REST 的精神一致。如果你還想再延伸,可以加上 authenticate(token) 自動加 Bearer 標頭,或加上錯誤處理(自動 raise 對應的例外)。本系列後續章節會逐步擴充這套介面。

另一個實用的工具是「HTTP 動詞與狀態碼速查表」。把它做成模組層級的常數,未來在 FastAPI 端點裡就可以直接引用,而不是寫魔術數字。

# http_constants.py
# HTTP 動詞與常用狀態碼的常數定義
from enum import IntEnum


class HttpMethod:
    GET = "GET"
    POST = "POST"
    PUT = "PUT"
    PATCH = "PATCH"
    DELETE = "DELETE"
    HEAD = "HEAD"
    OPTIONS = "OPTIONS"


class StatusCode(IntEnum):
    OK = 200
    CREATED = 201
    NO_CONTENT = 204
    BAD_REQUEST = 400
    UNAUTHORIZED = 401
    FORBIDDEN = 403
    NOT_FOUND = 404
    CONFLICT = 409
    UNPROCESSABLE_ENTITY = 422
    INTERNAL_SERVER_ERROR = 500
    BAD_GATEWAY = 502
    SERVICE_UNAVAILABLE = 503


# 用法示範
def describe(code: int) -> str:
    descriptions = {
        StatusCode.OK: "成功",
        StatusCode.CREATED: "資源已建立",
        StatusCode.NO_CONTENT: "成功但無回應主體",
        StatusCode.BAD_REQUEST: "請求格式錯誤",
        StatusCode.NOT_FOUND: "找不到資源",
        StatusCode.UNPROCESSABLE_ENTITY: "請求格式對了,但內容驗證失敗",
        StatusCode.INTERNAL_SERVER_ERROR: "伺服器內部錯誤",
    }
    return descriptions.get(code, "未知狀態碼")


print(describe(StatusCode.NOT_FOUND))
# 輸出:找不到資源

這個 http_constants.py 是後端專案的常見小工具——把所有會用到的 HTTP 概念集中在一個地方,避免散落在各處。實務上你會把這個檔案放到 src/<project>/constants.py 裡,讓所有端點與客戶端都能引用。IntEnum 的好處是「值等於意義」,但 IDE 與型別檢查器都能給你自動完成與跳轉。

到這裡我們已經把 HTTP 與 REST 的核心觀念走完——協定、請求回應、方法、等冪、狀態碼、設計原則,以及一個能實際跑的 hello-api RESTful 範例。明天我們會進入 FastAPI 的細節:路由、Pydantic v2 資料模型、以及那兩份會自動長出來的說明頁面。你會看到 FastAPI 怎麼把今天這些觀念變成「型別提示就是規格、規格就是測試」的設計。

補充:HTTP 設計的反例與啟示

理解 REST 最好的方式之一是看反例。SOAP 是 2000 年代初期主流的 API 風格,它把方法、參數、回應都包在一段 XML 裡,每個動作都有自己的動詞型動詞 GetUserById、CreateOrder,就像 RPC 一樣。SOAP 確實能解決當時企業團隊整合的問題,卻缺了不少方法:因為每個動詞都是自訂的,方法行為與 HTTP 動詞綁定的,規格書必須另外寫;對早中期 HTTP 快取頻寬驗證不友善。REST 的反應語意帶來幾組優勢,這次把幾組動作一個一個拿出來看。SOAP 雖然已經主流化了,但統一標準的演化仍然在 REST 圖譜裡繼續進行。

效能與實務提醒

REST 的無狀態特性對效能有兩個重要含意:第一,伺服器不需要保留 session,可以用任何一台機器處理請求,這對水平擴展(horizontal scaling)非常友善;第二,每個請求都帶著所有資訊(例如 token、查詢條件),所以請求體可能比有狀態設計稍大。實務上 token 通常只有幾百位元組,不是問題;查詢條件則要注意不要把整個篩選邏輯塞進 URL,可以用 POST + body(但這樣又違反 REST 的冪等性)或改用 GraphQL。

快取(cache)是另一個跟 HTTP 高度整合的議題。GET 請求應該可以被快取(瀏覽器、CDN、伺服器端),適當加上 Cache-Control、ETag、Last-Modified 標頭可以省下大量後端運算。Day 20 會介紹 Redis 快取,今天先把概念建立好。

API 版本管理也是 REST 設計的重要環節。常見做法是在 URL 加版本前綴(/v1/items、/v2/items),或是用 Accept 標頭做內容協商(Accept: application/vnd.myapi.v2+json)。前者比較直覺,後者更乾淨但較難除錯。我們這個系列會用前者,後續貫穿專案裡可以看到具體寫法。

小結

今天我們把 HTTP 與 REST 的核心觀念整理了一遍:HTTP 是無狀態的請求-回應協定,用方法與狀態碼表達動作與結果;REST 是一組設計原則,主張資源導向、統一介面、無狀態。我們把昨天的 hello-api 改寫成完整的 REST 風格 CRUD,端點語意清楚、狀態碼正確、用 Pydantic 自動驗證請求體,並用 httpx 走過一輪完整的建立、讀取、更新、刪除測試。這些觀念會在後續每天的 FastAPI 程式反覆出現,是整個系列最重要的基礎之一。

結語

今天我們停在「正確的 REST 慣例」這個關卡,看清楚了資源命名、方法、狀態碼之間的對應關係。明天,我們會進入 FastAPI 的核心機制:路由、Pydantic v2 的資料模型、以及 FastAPI 自動產生的 API 說明頁面(Swagger UI)。你會學到怎麼用裝飾器組合複雜的 URL 模式、用 Pydantic 設計嚴謹的請求與回應模型,以及怎麼讓 FastAPI 幫你寫說明頁面。

延伸資源

  • MDN Web Docs:HTTP 介紹(2025):https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Overview
  • RFC 9110:HTTP 語意(2022):https://www.rfc-editor.org/rfc/rfc9110
  • Roy Fielding 博士論文(2000):https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  • FastAPI 教學:Bigger Applications(2025):https://fastapi.tiangolo.com/tutorial/bigger-applications/
  • HTTP 狀態碼速查(HTTP Cats,2025):https://http.cat/
  • Pydantic v2 官方教學(2025):https://docs.pydantic.dev/latest/

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...