跳到主要內容

Web Day 30 Docker 化:從開發環境到容器

Web Day 30 Docker 化:從開發環境到容器

執行需求:需 Docker。這是「上線」章節的第一天,我們要把 Day 29 用環境變數管理設定的那支 FastAPI 服務,裝進 Docker 容器裡。整篇會走一條完整路線:先解釋 image / container / layer / volume 的差別,再寫一份精簡可跑的 Dockerfile 與 docker-compose.yml,最後用 curl 驗證容器內的服務能回應請求。為了照顧手上沒有 Docker 的讀者,文末有一段「不安裝 Docker」的替代流程;如果你能裝 Docker Desktop 或 OrbStack,建議同步對照,會更直觀。

引言

寫後端的同事常會遇到一種尷尬:在自己電腦跑得好好的程式,丟到同事的筆電或測試機就出錯。原因幾乎都脫離不了「環境不一樣」這四個字——Python 版本差一個小號、系統套件少裝一個、SQLite 路徑寫死、timezone 預設是 UTC,但部署機的時區是 Asia/Taipei。Docker 的核心價值就是把「執行環境」連同程式碼一起打包成一個可攜的單位,讓本機、測試機、正式機跑的是同一份 image。這一篇我們就要把那個單位做出來。

今天是上線章節的起點,後面 Day 31 會把 SQLite 換成 PostgreSQL 並用容器跑資料庫、Day 33 會在前面再加一層 Caddy 反向代理、Day 41 會把所有東西用 Docker Compose 一鍵打包。先把今天這份最小可跑的 Dockerfile 與 compose 檔案讀熟,後面幾天會在這個基礎上疊東西上去。

讀完今天,你會拿到四個具體的產物:一份可以一鍵 build 的 Dockerfile、一份帶 healthcheck 的 docker-compose.yml、一組驗證容器健康的 curl 指令、以及一份沒有 Docker 時的純本機替代流程。即使公司筆電沒開 Hyper-V,也能用替代流程把進度跟上;之後換到能跑 Docker 的環境,馬上就能切換成容器版本。

在開始之前,請確認手上的專案結構跟本篇範例一致:app/ 資料夾放程式碼,pyproject.toml 放依賴,Dockerfile 與 docker-compose.yml 放在專案根目錄。今天的所有指令都從這個根目錄執行,相對路徑就會跟範例一致。

容器化前要先懂的觀念

在動手寫 Dockerfile 之前,先把幾個關鍵名詞釐清,這能幫你理解後面每一行為什麼這樣寫。

Image 與 Container 的差別:image 是唯讀的樣板,類似「光碟片」或「程式安裝檔」;container 是 image 跑起來之後的執行實例,類似「光碟片裝進主機後正在執行的程式」。同一個 image 可以同時啟動多個 container,每個 container 都有自己的可寫層與獨立狀態(檔案系統、行程、網路)。正式環境通常會把同一個 image 開成多個 container,再由 load balancer 把流量分散過去,這就是水平擴展的基本動作。

Layer 的快取邏輯:Dockerfile 每一行指令都會產生一個 layer;build 時如果某一層的輸入沒變,Docker 會直接重用快取。這個特性決定了我們應該「先複製依賴檔、再複製原始碼」,因為原始碼改動是家常便飯,而依賴清單相對穩定。實務上常用 `docker build -t name:tag --no-cache .` 在 CI 強制重 build,確保不會被過期的 layer 影響。

Bind mount 與 Named volume:兩者都是把資料從主機放進容器的方式。bind mount 直接掛主機上的某個目錄(例如 ./data:/app/data),適合開發時即時看到程式改動;named volume 由 Docker 自己管理(通常放在 /var/lib/docker/volumes/),適合正式環境保存資料庫檔案,避免容器刪除後資料一起消失。今天的範例會用 named volume 保存 SQLite 檔。bind mount 在 Windows 與 macOS 上因為檔案系統差異,效能會略差,正式環境一律用 named volume 才穩定。

Docker Compose v2:從 Docker Desktop 4.x 開始,docker-compose v1(Python 寫的獨立 CLI)已經停止維護,官方推薦使用 Docker Engine 內建的 `docker compose`(沒有連字號)作為 Compose v2。設定檔仍叫 docker-compose.yml,但啟動指令從 `docker-compose up` 變成 `docker compose up`。本系列一律使用 Compose v2 語法。

Port 與網路:Docker 容器有自己的虛擬網路,預設不對外開放任何 port。要讓外面的瀏覽器或 curl 能打到容器內的服務,必須在 docker run 或 compose 用 `-p 主機:容器` 顯式把 port 對應出去。今天範例把容器內的 8000 對應到主機的 8000,因此可以從 `http://127.0.0.1:8000` 存取。同時,compose 內不同 service 之間可以用 service name 直接互通,不需要走主機的網路,這個特性會在 Day 31 把 PostgreSQL 變成獨立 service 時用到。

容器與虛擬機的差別:容器共用主機的 kernel,只有應用層隔離;虛擬機則連 kernel 都各自一份。容器的啟動時間通常在一秒內,虛擬機要數十秒到數分鐘;容器需要的資源(CPU、RAM)也比虛擬機少一個量級。這也是為什麼現代後端部署幾乎都走容器,VM 留給需要特定 kernel 版本或強隔離的場景。

專案結構與依賴

為了讓 Dockerfile 與 compose 檔的相對路徑容易理解,先把我們要打包的專案攤開來。整個範例只有五個檔案,分別是:pyproject.toml 宣告依賴、app/main.py 是 FastAPI 程式、app/__init__.py 讓資料夾成為套件、Dockerfile 是 image 的組裝說明、docker-compose.yml 是多容器編排設定。

booking-api/
├── app/
│   ├── __init__.py
│   └── main.py
├── pyproject.toml
├── .dockerignore
├── Dockerfile
└── docker-compose.yml

pyproject.toml 用來宣告這個專案用到的 Python 套件。我們選擇 PEP 621 標準格式,後續可以無痛接 uv 或 poetry。今天的範例只需要 fastapi、uvicorn 與 pydantic-settings 三個套件。

[project]
name = "booking-api"
version = "0.1.0"
description = "預約管理系統 API(範例)"
requires-python = ">=3.13"
dependencies = [
    "fastapi==0.116.*",
    "uvicorn[standard]==0.35.*",
    "pydantic-settings==2.11.*",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

接著是 FastAPI 主程式。為了聚焦在容器化這件事,路由刻意簡化,只有 / 與 /healthz 兩個端點;前者回應歡迎訊息,後者做為容器的健康檢查端點,後面 docker-compose.yml 會用到。

from fastapi import FastAPI
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", extra="ignore")
    app_name: str = "booking-api"
    db_path: str = "/data/booking.db"


settings = Settings()
app = FastAPI(title=settings.app_name)


@app.get("/")
def root() -> dict[str, str]:
    return {"service": settings.app_name, "status": "ok"}


@app.get("/healthz")
def healthz() -> dict[str, str]:
    return {"status": "healthy"}

撰寫 Dockerfile

Dockerfile 是 image 的組裝說明書。我們用 python:3.13-slim 作為基底——slim 變體只保留 Python 直譯器與必要系統套件,image 大小約 150 MB,比完整的 python:3.13(接近 1 GB)小很多。對正式環境來說,image 每小 100 MB,pull 與 push 就省幾秒到幾分鐘。

FROM python:3.13-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1

RUN groupadd --system app
RUN useradd --system --gid app --create-home --home-dir /app app

WORKDIR /app

COPY pyproject.toml ./
RUN pip install --no-cache-dir --upgrade pip
RUN pip install --no-cache-dir .

COPY app ./app

USER app

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

這份 Dockerfile 有幾個刻意的小地方值得說明:第一,`PYTHONDONTWRITEBYTECODE=1` 防止 .pyc 寫進容器,減少 image 體積;第二,`PYTHONUNBUFFERED=1` 讓 uvicorn 的 log 直接送到 stdout,方便 `docker logs` 即時看到;第三,把安裝依賴與複製原始碼分成兩段,這樣只改 main.py 時 pip install 那一層會被 cache 住;第四,最後 `USER app` 切到非 root,這是容器安全的基本功;第五,`EXPOSE 8000` 是文件性質的宣告,真正把 port 對外是 docker compose 或 docker run 的工作。

.dockerignore 與 docker-compose.yml

.dockerignore 的角色類似 .gitignore,告訴 Docker build 時哪些檔案不要送進 context。沒設定這個檔案會讓 .env、.venv、__pycache__、測試報告等不該進 image 的東西全部被 COPY 進去,既增加 image 大小,也可能意外把 secrets 包進 image 推上 registry。

.git
.gitignore
.venv
venv
__pycache__
*.pyc
*.pyo
.pytest_cache
.mypy_cache
.ruff_cache
htmlcov
.coverage
.env
.env.*
README.md
docs
tests
data

docker-compose.yml 是多容器編排的核心。我們只啟動一個服務(api),但用 named volume 把 SQLite 檔案保存起來,並加上 healthcheck 讓 Docker 自己判斷容器是否健康。

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    image: booking-api:dev
    container_name: booking-api
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      APP_NAME: booking-api
      DB_PATH: /data/booking.db
    volumes:
      - booking-data:/data
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=2).status == 200 else 1)"]
      interval: 10s
      timeout: 3s
      retries: 5
      start_period: 10s

volumes:
  booking-data:

這份 compose 檔有三個關鍵設計:`volumes` 用 named volume `booking-data` 保存 SQLite 檔,容器被刪除後資料還在;`healthcheck` 每 10 秒打一次 /healthz,連續失敗 5 次才標記為 unhealthy;`restart: unless-stopped` 讓主機重開機後容器會自動重啟,模擬正式環境的行為。健康檢查的指令刻意用 Python 而非 curl,因為 slim 映像沒有裝 curl,能減少 image 體積。

建置、啟動與驗證

前面準備好之後,剩下幾個指令就能把整套東西跑起來。第一次 build 需要下載 python:3.13-slim 並安裝套件,大約 1 到 2 分鐘;之後改 code 再 build,只會重做有變動的 layer,通常 5 秒內完成。

docker compose build              # 建置 image
docker compose up -d               # 背景啟動 container
docker compose ps                  # 查看狀態(STATUS 應為 healthy)
curl http://127.0.0.1:8000/         # 輸出:{"service":"booking-api","status":"ok"}
curl http://127.0.0.1:8000/healthz  # 輸出:{"status":"healthy"}
docker compose logs api             # 查看 API log
docker compose down                # 停止並移除 container(volume 保留)

驗證時請特別看 `docker compose ps` 的 STATUS 欄。如果顯示 `Up X seconds (healthy)` 表示 healthcheck 通過;如果停在 `Up X seconds (health: starting)` 表示容器剛啟動還在等 start_period;如果變成 `Up X seconds (unhealthy)` 表示 healthcheck 連續失敗,需要用 `docker compose logs api` 看 log 找原因。如果想看更詳細的 log,可以加 `docker compose logs -f api` 持續追蹤。

進入容器內除錯時,`docker compose exec api /bin/bash` 可以開一個互動 shell;這個指令常用在「程式在容器裡跑得好好的,本機跑卻壞掉」的情境,讓你確認容器內的環境是否符合預期。SQLite 檔可以從主機用 `docker compose exec api sqlite3 /data/booking.db` 開 shell,但今天的範例還沒用到資料庫,先當作備忘。

如果你想要看容器內的 Python 環境,底下的腳本會列出容器內已安裝的套件與版本,並把它跟主機的 Python 比較。差異通常就是「為什麼程式在本機能跑、容器內不能跑」的線索來源。

import subprocess
import sys


def list_packages_in_container(container: str) -> str:
    """呼叫 docker compose exec 在容器內列出 pip 套件。"""
    cmd = ["docker", "compose", "exec", container, "pip", "list", "--format=json"]
    result = subprocess.run(cmd, capture_output=True, text=True, check=True)
    return result.stdout


def parse_packages(payload: str) -> dict[str, str]:
    """把 pip list 的 JSON 輸出轉成名稱→版本的字典。"""
    import json
    return {item["name"].lower(): item["version"] for item in json.loads(payload)}


if __name__ == "__main__":
    payload = list_packages_in_container("api")
    container_pkgs = parse_packages(payload)
    key = "fastapi"
    print(f"容器內 fastapi 版本:{container_pkgs.get(key, '未安裝')}")
    print(f"主機 fastapi 版本:{__import__('fastapi').__version__}")
    if container_pkgs.get(key) != __import__("fastapi").__version__:
        sys.exit("版本不一致,請重新 build image")

這個小工具的概念是「把容器當黑盒,用 subprocess 呼叫 docker CLI 觀察它的狀態」。`subprocess.run` 在容器不存在時會拋出 `CalledProcessError`,可以把那段包成 try/except 變成更友善的錯誤訊息。實務上這個手法常用在 CI 跑整合測試時的環境驗證,例如在 GitHub Actions 裡比對容器與本機的 Python 版本是否符合預期。

另一個驗證 named volume 真的有保存資料的小腳本:用 docker compose down 把容器刪掉,再啟動一次,看 SQLite 檔案是否還在。

import os
import subprocess
from pathlib import Path


def volume_ls(volume_name: str) -> list[Path]:
    """列出 named volume 內的檔案,用 docker volume inspect 取得掛載點。"""
    cmd = ["docker", "volume", "inspect", volume_name, "--format", "{{.Mountpoint}}"]
    mountpoint = subprocess.run(cmd, capture_output=True, text=True, check=True).stdout.strip()
    if not mountpoint:
        return []
    return sorted(Path(mountpoint).iterdir())


if __name__ == "__main__":
    files_before = volume_ls("booking-data")
    print(f"關閉容器前的 volume 內容:{[f.name for f in files_before]}")

    subprocess.run(["docker", "compose", "down"], check=True)
    subprocess.run(["docker", "compose", "up", "-d"], check=True)

    files_after = volume_ls("booking-data")
    print(f"重啟容器後的 volume 內容:{[f.name for f in files_after]}")
    assert files_before == files_after, "named volume 沒有保存資料"

這個腳本示範了 named volume 的核心價值:容器可以反覆重建,但資料不會跟著消失。我們用 `docker volume inspect` 拿到 volume 在主機上的掛載點,再列舉裡面的檔案。這個模式在 Day 31 換成 PostgreSQL 之後會更重要,因為資料庫檔案通常都是放在 named volume 裡,容器一升級資料就掉可不是開玩笑。

沒有 Docker 時的替代流程

不是每台電腦都能裝 Docker(特別是公司配的 Windows 筆電,可能沒開 Hyper-V)。如果你目前無法跑 Docker,可以改用下面這套完全在本機執行的流程,所有功能與容器內版本一致,只是少了「環境封裝」這一層。

python -m venv .venv              # 建立虛擬環境
source .venv/bin/activate          # macOS / Linux
# .venv\Scripts\activate           # Windows PowerShell
pip install --upgrade pip
pip install -e .                   # 以可編輯模式安裝(依 pyproject.toml)
uvicorn app.main:app --reload --port 8000

這條流程用 Python 官方 venv + pip 安裝,跟 Dockerfile 裡的安裝步驟用同一份 pyproject.toml,所以套件版本一定一致。差別只在「應用直接跑在主機 Python 上」而不是容器裡。等之後拿到能裝 Docker 的環境,再切回 `docker compose up` 就好,程式碼完全不需要改。SQLite 檔也從容器內的 /data/booking.db 變成 ./booking.db,路徑由 .env 裡的 DB_PATH 控制。

常見錯誤與踩雷

把 .env 一起 COPY 進 image。如果 .dockerignore 沒寫好,build context 裡的 .env 會被 COPY 進 image,之後 image 推到 registry 就會把 secrets 一起送出去。務必在 .dockerignore 加上 .env,並在 compose 裡用 `environment` 或 `env_file` 顯式注入;千萬別把 .env 寫進 image。如果真的不小心把 secrets 推上 Docker Hub,記得立刻 rotate 並從 registry 刪除,否則可能被自動化掃描工具撈走。

用 root 跑應用。預設 Docker container 內的 process 是 root,這代表容器被入侵時攻擊者直接拿到主機 root。今天的 Dockerfile 已經用 `useradd` 建了 app 帳號並切換過去,但很多人會忘記這一步,請記得加上 `USER app`。如果 image 已有 root 寫的檔案,記得在 COPY 後用 `chown -R app:app /app`,不然非 root 帳號會因為沒寫入權限而啟動失敗。

bind mount 在容器內寫入 SQLite 的權限問題。如果用 `./data:/app/data` 這種 bind mount,容器內的 app 帳號可能沒辦法寫入主機的 ./data 目錄(特別是 UID 不對應時)。解法有三種:把目錄 chown 給對應的 UID、用 named volume、或者用 `:cached` / `:delegated` 等 mount option。範例程式為了簡化,採用 named volume 是最不容易踩雷的做法。

build 完 image 卻沒重啟 container。改了程式碼之後只跑 `docker compose build` 不會自動重啟,要再跑 `docker compose up -d` 才行。如果想要「改 code 後自動重啟」,可以掛上 volumes 並把 uvicorn 換成 `--reload`,但 production 不要這樣做。`--reload` 會額外開檔案監聽 process,浪費記憶體且可能影響 hot path 效能。正式環境的更新流程應該是:build 新 image → push 到 registry → 用新 image 啟動新 container → 流量切換 → 關掉舊 container,這個流程在 Day 32 與 Day 41 都會再示範。

沒有指定 image tag。如果 docker-compose.yml 沒寫 `image: booking-api:dev`,compose 會用「目錄名-服務名」組合的 `latest` 作為預設 tag,例如 `booking-api_api:latest`。這個 latest tag 容易被覆寫、難以追蹤版本,正式部署一定要明確標 tag(例如對應 Git commit SHA)。

忘記設定 timezone。容器預設使用 UTC 時區,跟台灣(UTC+8)差 8 小時,log 時間戳記會跟使用者的當地時間對不上。可以在 Dockerfile 加上 `ENV TZ=Asia/Taipei`,或在 compose 用 `environment: TZ: Asia/Taipei` 顯式注入。後者比較好維護,因為不同環境(測試、正式)可以各自覆寫。

效能與實務提醒

image 大小會直接影響 CI 的 build 時間與部署時的 pull 時間。三個常用瘦身手段依序是:用 slim 或 alpine 基底(從 1 GB 降到 150 MB)、用 multi-stage build 把編譯工具留在 builder stage(最終 image 不需要)、用 `pip install --no-cache-dir` 與 `PYTHONDONTWRITEBYTECODE=1` 減少中間產物。今天的範例已經做了前兩者,後續章節若需要 C 編譯(例如某些加密套件),會再示範 multi-stage。

layer 快取的正確順序很重要:「不常變動的層放前面,常變動的放後面」。所以才會先 COPY pyproject.toml、再 COPY app/。如果你反過來寫,每次改 main.py 都要重跑 pip install,build 時間會從 5 秒膨脹到 1 分鐘以上,CI 跑久了成本驚人。要看哪一層佔空間可以用 `docker history booking-api:dev`,每一層都會列出大小與建立指令。

正式環境務必把 uvicorn 的 `--reload` 拿掉,並考慮改用 `uvicorn --workers 4` 啟動多個 worker 撐住流量。容器內一般建議搭配 gunicorn 或 uvicorn 的 process 管理方式,今天先用最簡的單 worker 範例走完流程,後續章節會再談水平擴展。另一個實務提醒是「不要在容器裡跑多個無關服務」:每個容器只做一件事,擴展與故障隔離都比較好處理,這也是後面 docker-compose.yml 把資料庫拆成獨立服務的原因。

小結

今天我們從「環境一致」的需求出發,寫了第一份 Dockerfile 與 docker-compose.yml,把 FastAPI 服務裝進容器並驗證健康檢查。重點觀念包括:image 與 container 的差別、layer 的快取邏輯、bind mount 與 named volume 的取捨、為什麼要用 .dockerignore 與非 root 帳號。文末也提供了不安裝 Docker 時的替代本地流程,確保每位讀者都能在今天的進度上往前推進。明天我們會把容器內的 SQLite 換成正式環境等級的 PostgreSQL,並用容器跑資料庫。

結語

Docker 是上線章節的地基,今天打地基、明天疊牆。掌握好 Dockerfile 與 compose 的基本寫法,後面 Day 33 的反向代理、Day 41 的多容器一鍵部署都會在這個基礎上擴充。明天,我們會把 SQLite 換成 PostgreSQL、用容器跑資料庫,並討論連線池與遷移指令怎麼串進容器啟動流程。

延伸資源

  • Docker 官方文件:https://docs.docker.com/engine/(Docker Engine 27.x 世代)
  • Docker Compose 規格說明:https://docs.docker.com/compose/compose-file/(Compose v2)
  • python:3.13-slim 映像說明:https://hub.docker.com/_/python
  • FastAPI 官方部署指南:https://fastapi.tiangolo.com/deployment/docker/
  • PEP 621 套件中繼資料標準:https://peps.python.org/pep-0621/

留言

這個網誌中的熱門文章

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 建構深度學習模型。 開發者與研究人員 :想更深入了...