Python

程式架構是什麼?看懂 AI 寫的模組、例外處理與 class

程式架構是模組、例外處理、class 與檔案讀寫這些組織程式的方式,AI 產出的程式碼幾乎都會用到。看懂 import 怎麼選、try 和 except 的流程、class 的 __init__ 和 self,還有 with open 讀寫檔案,你才能判斷 AI 給的程式碼安不安全、好不好維護。
程式架構是什麼?看懂 AI 寫的模組、例外處理與 class

程式架構是什麼?看懂 AI 寫的模組、例外處理與 class

AI 給你的程式只要超過幾十行,一定會拆成模組、例外處理、class 這些基本架構。你不需要自己動手全部寫出來,但看不懂架構,就沒辦法判斷 AI 寫的程式碼安不安全、會不會一遇到錯誤就當機。

這篇文章帶你讀懂 import 怎麼選、try / except 怎麼寫才不會吞掉錯誤、class__init__self 在做什麼,還有安全讀寫檔案的 with open,最後附上三道可以馬上練習的題目。

你將學到什麼

模組與套件

分清楚 import 的三種寫法,看懂哪些函式庫需要先安裝。

例外處理

用 try / except / finally 讓程式優雅失敗,不再一遇到錯誤就當機。

class 入門

讀懂 __init__ 和 self,看懂 AI 怎麼把邏輯封裝起來。

檔案讀寫

用 with open 安全讀寫檔案和 JSON,不怕忘記關閉檔案。

AI 常見架構陷阱

抓出忘記 encoding、裸露 import *、忘記用 with 這三個常見地雷。

為什麼 Vibe Coder 要懂程式架構?

看懂 AI 怎麼組織程式
  • 讀懂 AI 給的完整專案:程式只要超過幾十行,AI 幾乎都會拆成函式、class、模組,你要看得懂它怎麼組織。
  • 程式不會動不動就當機:例外處理是讓程式優雅失敗的關鍵,沒有 try / except,一個錯誤就會讓整個程式停掉。
  • 讓 AI 寫出可以重複使用的程式:知道 class 是什麼,才能告訴 AI 把某段邏輯封裝成一個 class,讓程式更好維護。
  • 安全讀寫檔案with open() 是讀寫檔案的標準寫法,不用它可能讓檔案沒有正確關閉而損毀。
本篇核心問題

看到 AI 給的程式,問自己三件事:

  • 它 import 了什麼?哪些是標準函式庫,哪些需要先 pip install
  • 出錯時會怎樣?有沒有 try / except?錯誤訊息看得懂嗎?
  • 為什麼要用 class?它在封裝什麼樣的狀態和行為?

模組與套件:import 的正確姿勢

模組(module)是一個 .py 檔案,套件(package)是一個資料夾,裡面放了很多模組。AI 幾乎每一份程式都從 import 開始,你要能一眼分辨它 import 的是哪一種。

# 方式一:import 整個模組(用「模組名.函式」呼叫)
import os
print(os.getcwd())          # 取得目前所在目錄

# 方式二:只 import 需要的部分(可以直接呼叫)
from os.path import join, exists
print(join("data", "file.csv"))   # "data/file.csv"

# 方式三:import 並取別名(模組名稱太長時常用)
import datetime as dt
print(dt.date.today())

# 常見標準函式庫速查
import os          # 作業系統操作(路徑、目錄)
import sys         # Python 執行環境
import json        # JSON 讀寫
import re          # 正規表達式
import datetime    # 日期時間
import pathlib     # 路徑操作(現代寫法)
觀察重點:標準函式庫 vs 第三方套件標準函式庫(osjsonre)不用安裝,Python 內建就有;第三方套件(requestspandasopenai)需要先 pip install 套件名。看到 AI 的 import 清單,哪些要先裝好是你必須判斷的事。

例外處理:try / except / finally

例外處理讓程式在遇到錯誤時可以優雅失敗,而不是直接當機。任何可能失敗的操作,像是網路、檔案、型別轉換、呼叫 API,都應該包在 try 裡面

執行 try 區塊發生例外?except攔截並處理例外else略過 except,直接往下執行finally不論成功或失敗都會執行
try 例外處理的判斷流程:執行 try 區塊,發生例外就用 except 攔截,沒有例外則往下執行,finally 不論如何都會執行。
# 基本結構
try:
    result = int(input("輸入數字:"))
    print(100 / result)
except ValueError:
    print("請輸入有效的數字")     # 型別轉換失敗
except ZeroDivisionError:
    print("不能除以零")           # 除以零
except Exception as e:
    print(f"未預期的錯誤:{e}")   # 捕捉所有其他例外
else:
    print("成功!")               # try 沒有例外時執行
finally:
    print("不管成功或失敗都執行") # 常用來關閉資源
try:
    do_something()
except:               # 什麼例外都捕捉,連 KeyboardInterrupt 也吞掉!
    pass               # 靜默忽略,根本不知道出了什麼問題
危險:裸露的 except 會吞掉所有錯誤上面這種寫法連 KeyboardInterrupt 都會被攔下來,出錯時整個程式安靜地什麼事都沒發生,你完全不知道哪裡壞了。看到 AI 寫 except:except Exception: pass,要求它改成指定明確的例外類型,並且加上錯誤記錄,不要靜默吞掉錯誤。
觀察重點看到 AI 的程式裡有 try,先問:它捕捉的例外類型夠明確嗎?出錯時有沒有印出訊息?如果只有一個空空的 except: pass,就是該請 AI 補上防護的時候。

class 入門:讀懂 __init__ 與 self

class(類別)是把資料(屬性)和行為(方法)打包在一起的方式。你不需要自己常常寫 class,但 AI 給的程式常常用 class 組織邏輯,你要能讀懂 __init__self、方法在做什麼

class Student:
    def __init__(self, name, score):   # 建構子:建立實例時執行
        self.name = name              # self.xxx 是實例屬性
        self.score = score

    def grade(self):                  # 實例方法,第一個參數固定是 self
        if self.score >= 90:
            return "優秀"
        elif self.score >= 60:
            return "及格"
        return "不及格"

    def __repr__(self):               # 決定 print(物件)的顯示方式
        return f"Student({self.name}, {self.score})"

# 建立實例
alice = Student("Alice", 92)
print(alice.name)     # "Alice"
print(alice.grade())  # "優秀"
print(alice)          # Student(Alice, 92)
觀察重點:三個關鍵字
  • __init__:建構子,建立物件時自動執行,用來設定初始值
  • self:代表「這個實例本身」,所有方法的第一個參數都是 self
  • self.屬性:這個物件自己的資料,每個實例各自獨立

檔案讀寫與 with 語法

with open() 是 Python 讀寫檔案的標準寫法,執行完會自動關閉檔案,不需要手動呼叫 .close() 這個動作。AI 寫的所有檔案操作都應該用這個模式

# 讀取文字檔
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()          # 讀取全部
    lines = f.readlines()       # 讀取成串列(每行一個元素)

# 寫入文字檔
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("Hello\n")          # "w" 覆蓋寫入

with open("log.txt", "a", encoding="utf-8") as f:
    f.write("新的一行\n")        # "a" 附加在結尾

# 讀寫 JSON(最常見)
import json

with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)         # JSON 轉換成 Python 的 dict 或 list

with open("output.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
模式說明檔案不存在時
"r"讀取(預設模式)會拋出 FileNotFoundError
"w"覆蓋寫入自動建立新檔
"a"附加在檔案結尾自動建立新檔
"x"建立新檔,檔名不能重複自動建立;已存在會拋錯

AI 常見架構陷阱

陷阱一:忘記指定 encoding,中文會變亂碼

# ❌ 沒有指定 encoding,在 Windows 上中文可能會變亂碼
with open("data.txt", "r") as f:
    content = f.read()

# ✅ 永遠指定 encoding="utf-8"
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()
為什麼一定要加 encodingWindows 預設用系統編碼(通常是 cp950),沒有指定 encoding="utf-8" 的話,讀寫中文檔案很容易變成亂碼。養成習慣,open() 一律加上 encoding="utf-8"

陷阱二:裸露 import *,污染命名空間

# ❌ from module import * 把所有名稱都引進來
from os import *       # os 的所有函式都被引進來,可能蓋掉你自己寫的函式
import * 的風險裸露的 import * 會把模組裡所有名稱都引進來,可能不小心蓋掉你自己寫的函式,也讓人搞不清楚某個名稱到底從哪裡來。改成具名 import,或是 import 模組名 再用 模組名.函式 呼叫,才看得出來源。

陷阱三:不用 with,手動 open 和 close 容易忘記

# ❌ 手動 open / close,例外發生時 close 永遠不會被執行
f = open("data.txt")
data = f.read()
f.close()

# ✅ 用 with open,不管有沒有例外都會自動關閉
with open("data.txt", encoding="utf-8") as f:
    data = f.read()
三條 import 與資源管理紀律不要用 import *;標準函式庫的 import 放最前面,第三方套件放後面;拿到 AI 的程式,把 import 清單複製給它,問清楚哪些需要先 pip install

三道遞進題:讀懂、改寫、抓錯

這三題由淺入深:先讀懂 class 加 try / except 加 with open 混在一起時的執行流程,再練習請 AI 補上完整的例外處理,最後自己抓出 import、encoding、裸露 except 這些最常見的架構地雷。

題目一:讀懂(基礎)

class FileReader:
    def __init__(self, path):
        self.path = path

    def read(self):
        try:
            with open(self.path, encoding="utf-8") as f:
                return f.read()
        except FileNotFoundError:
            return None

reader = FileReader("notes.txt")
content = reader.read()
print(content)

任務:說明 __init__ 做了什麼、read() 方法的執行流程,以及如果 notes.txt 不存在,print(content) 會輸出什麼。

  1. __init__ 把傳入的 path 存成 self.path,讓整個 class 都能使用。
  2. read() 方法用 with open 安全讀取檔案,並且用 try / except 捕捉 FileNotFoundError
  3. 檔案不存在時,就會拋出 FileNotFoundError,被 except 捕捉後回傳 None,所以 print(content) 顯示的是 None

題目二:改寫(進階)

為什麼要懂例外處理的分層AI 給的初版程式常把所有例外混在同一個 except 裡處理,或是乾脆完全不處理例外。真實情境需要分層:網路錯誤、檔案錯誤、型別錯誤各自需要不同的處理方式,你要能告訴 AI 正確的分層寫法。
import json

def load_config(path):
    f = open(path)
    data = json.load(f)
    f.close()
    return data["settings"]

請改進 load_config 函式,加上:

  • with open 取代手動 open / close
  • encoding="utf-8"
  • try / except 分別處理三種例外:FileNotFoundError 印出找不到檔案的訊息並回傳 Nonejson.JSONDecodeError 印出 JSON 格式錯誤並回傳 NoneKeyError 印出缺少 settings 欄位並回傳空的 dict

請加上 docstring 和中文註解。

可以直接貼給 AI 的提示詞
  1. open / close 換成 with open(path, encoding="utf-8") as f,讓檔案自動關閉,也避免中文亂碼。
  2. 三個 except 分別處理三種不同錯誤,各自印出有意義的訊息,不再靜默失敗。
  3. KeyError 回傳 {}(空的 dict)而不是 None,讓呼叫端能安全地繼續使用 dict 操作。

題目三:抓錯(高階)

架構上的錯誤往往在小專案裡看不出問題,等專案變大才會爆出來。你要在 AI 給程式的當下就看出潛在問題,不要等到上線才發現。

from os import *
from json import *

class DataProcessor:
    records = []                  # 類別屬性,所有實例共用!

    def add(self, item):
        self.records.append(item)

    def save(self, path):
        try:
            f = open(path, "w")
            f.write(dumps(self.records))
            f.close()
        except:
            pass

任務:找出至少三個問題,說明每個問題的危險原因,並寫出可以請 AI 修正的提示詞。

問題一:import * 污染命名空間from os import *from json import * 把所有名稱都引進來,dumps 等函式來源不清楚,也可能被覆蓋。應該改成 import json,再用 json.dumps() 呼叫。
問題二:類別屬性 records 被所有實例共用records = [] 寫在 class 層級,是類別屬性,所有 DataProcessor 的實例會共用同一份清單。應該搬進 __init__,改成 self.records = []
問題三:裸露的 except 吞掉所有錯誤save() 出錯時完全靜默,使用者不會知道是路徑錯誤、磁碟空間不足,還是其他原因。應該指定明確的例外類型,並且印出錯誤訊息。

術語速查表

術語說明
module(模組)一個 .py 檔案;package(套件) 是包含多個模組的資料夾。
import X引入整個模組,用 X.函式() 呼叫。
from X import Y只引入模組裡的特定部分,可以直接用 Y() 呼叫。
import X as Y引入並取別名,常見的例子像 import numpy as np
標準函式庫 vs 第三方套件標準函式庫不需要安裝就能用;第三方套件需要先用 pip install 安裝。
try / except例外處理的基本結構;except 例外類型 as e 可以取得例外物件本身。
finally不管 try 成功或失敗都會執行,常用來關閉資源。
raise主動拋出一個例外,例如 raise ValueError("訊息") 這種寫法。
class定義一個類別(藍圖),用 類別名() 建立一個實例(物件)。
__init__(self)建構子,在建立實例時自動被呼叫,用來設定初始屬性。
self代表實例本身;self.屬性 是屬於這個實例自己的資料。
類別屬性 vs 實例屬性類別屬性所有實例共用;實例屬性在 __init__ 裡定義,每個物件各自獨立。
with open() as f安全讀寫檔案,執行完自動關閉,不用手動呼叫 .close() 就好。
encoding="utf-8"讀寫中文檔案時一定要指定,否則 Windows 預設的編碼可能會讓中文亂碼。
json.load(f) 從檔案物件讀取 JSON 內容;json.loads(字串) 是從字串讀取。

重點整理與自我檢查

概念記憶要點
import 選擇具名 import,不用 *;標準函式庫放前面
try / except指定明確的例外類型,不要裸露;也不要靜默吞掉錯誤
class 三個關鍵__init__self、實例屬性 vs 類別屬性
檔案讀寫永遠用 with open,永遠加 encoding="utf-8"
Vibe Coder 架構三問import 了什麼,需要安裝嗎?出錯時會怎樣,有 try / except 嗎?class 的屬性寫在 __init__ 裡還是外面,是共用還是各自獨立?

自我檢查清單

  • 能分辨標準函式庫和第三方套件,知道哪些需要先 pip install
  • 能讀懂 try / except / else / finally 的執行順序
  • 知道裸露的 except: pass 有多危險,會主動請 AI 改善
  • 能讀懂 class 的 __init__self、方法怎麼寫
  • 知道類別屬性和實例屬性的差別
  • 能用 with open(encoding="utf-8") 讀寫中文檔案
  • 完成題目一:說明 class 加 try 加 with 混合使用時的執行流程
  • 完成題目二:請 AI 加上分層的例外處理
  • 完成題目三:找出 import *、類別屬性共用、裸露 except 這三個問題

延伸學習

把這篇文章分享給需要的人FacebookLINEThreadsX

常見問答

標準函式庫和第三方套件差在哪?
標準函式庫(像 os、json、re)是 Python 內建的,不用另外安裝;第三方套件(像 requests、pandas)需要先用 pip install 安裝才能 import。看到 AI 給的程式碼,先分清楚哪些要先裝好。
為什麼不能用裸露的 except?
裸露的 except 不指定例外類型,會把所有錯誤都吞掉,包含你根本不知道發生什麼事的錯誤,甚至連 KeyboardInterrupt 都會被攔下來。正確做法是指定明確的例外類型,並且印出錯誤內容,不要靜默忽略。
class 裡的類別屬性和實例屬性差在哪?
寫在 class 內、__init__ 外面的是類別屬性,所有實例共用同一份;寫在 __init__ 裡的 self 屬性是實例屬性,每個物件各自獨立。AI 常把該獨立的資料誤放成類別屬性,要特別檢查。
為什麼讀寫檔案一定要用 with open?
with open 會在程式離開這個區塊時自動關閉檔案,就算中途發生例外也一樣;如果是手動 open 再 close,只要例外提早發生,close 那一行就永遠執行不到,檔案可能沒有正確關閉。