載入中…
載入中…
三種難度,涵蓋 Python、C# 與 Web 開發,動手練習加深理解。
共 26 道練習題
請撰寫一個程式,讓使用者輸入身高(公分)與體重(公斤),計算並顯示 BMI 指數,並判斷體重狀態(過輕 / 正常 / 過重 / 肥胖)。
BMI = 體重(kg) / 身高(m)²,記得將身高從公分轉換成公尺。
# 計算 BMI 指數並判斷體重狀態
height_cm = float(input("請輸入身高(公分):"))
weight_kg = float(input("請輸入體重(公斤):"))
# 身高從公分轉換成公尺
height_m = height_cm / 100
bmi = weight_kg / (height_m ** 2)
# 依 BMI 範圍判斷體重狀態
if bmi < 18.5:
status = "過輕"
elif bmi < 24:
status = "正常"
elif bmi < 27:
status = "過重"
else:
status = "肥胖"
print(f"你的 BMI 是 {bmi:.2f},體重狀態:{status}")
使用巢狀迴圈印出完整的九九乘法表,每一行要對齊,格式如:1×1=1 1×2=2 ...
使用兩層 for 迴圈,外層控制被乘數,內層控制乘數,用 end="" 避免自動換行。
# 印出九九乘法表,每一行對齊
# 外層迴圈:被乘數 1~9
for i in range(1, 10):
# 內層迴圈:乘數 1~9
for j in range(1, 10):
# 用 :2 讓數字靠右對齊寬度 2,維持每欄整齊
print(f"{i}×{j}={i * j:<2}", end=" ")
# 每跑完一行(內層迴圈結束)才換行
print()
撰寫一個 C# 主控台程式,讓使用者輸入身高(公分)與體重(公斤),計算並輸出 BMI 與健康判定;再加做一個公里/英里的單位換算。重點在變數、型別轉換與 Console 輸入輸出。
BMI = 體重(kg) / (身高(m))²,記得把公分換算成公尺;用 double.TryParse() 處理輸入錯誤。
用純 JavaScript 建立待辦清單:可新增項目(按 Enter 或按鈕)、點擊項目標記完成(顯示刪除線)、點擊 ✕ 刪除項目、顯示剩餘未完成數量。
用 event delegation 在父元素監聽子元素的點擊事件,避免對每個項目個別監聽。
建立一個報名表單(姓名、Email、電話、密碼、確認密碼),實作即時驗證:每個欄位 blur 時檢查,錯誤訊息顯示在欄位下方,所有欄位正確才能提交。
用正規表達式驗證 Email 格式,密碼比對在兩個密碼欄位的 input 事件中即時更新。
使用 Open-Meteo 免費 API(無需 API Key),建立天氣查詢應用:輸入城市名稱後取得當前天氣與未來 7 天預報,用圖表顯示溫度趨勢。
先用 Nominatim API 將城市名轉換成經緯度,再呼叫 Open-Meteo API 取得天氣資料,用 Canvas 或 SVG 畫折線圖。
建立一個使用者列表頁面,從 JSONPlaceholder API 取得 10 筆使用者資料,實作即時搜尋(輸入名稱立即篩選),並加入 loading 與 error 狀態。
用 useEffect 的 cleanup function 取消前一次請求,或搭配 AbortController 避免 race condition。
用 React + React Router 建立購物車應用:商品列表頁、商品詳情頁、購物車頁。實作加入購物車、修改數量、刪除商品、計算總金額功能。
購物車狀態用 useContext + useReducer 管理,或用 Zustand 套件。使用 localStorage 讓資料在重新整理後保留。
撰寫一個函式 calculator(a, op, b),支援加減乘除四種運算。需要處理除以零的錯誤情況,並讓使用者可以重複輸入直到輸入 q 退出。
用 try/except 處理 ZeroDivisionError,用 while 迴圈讓程式持續執行。
# 簡易計算機:支援加減乘除,可重複輸入直到輸入 q 退出
def calculator(a, op, b):
"""依運算符號 op 計算 a 與 b,回傳結果字串"""
try:
if op == "+":
return a + b
elif op == "-":
return a - b
elif op == "*":
return a * b
elif op == "/":
return a / b
else:
return "不支援的運算符號(僅支援 + - * /)"
except ZeroDivisionError:
return "錯誤:除數不可為 0"
while True:
raw = input("請輸入運算式(格式:數字 運算符 數字,輸入 q 離開):").strip()
if raw.lower() == "q":
print("再見!")
break
try:
a_str, op, b_str = raw.split()
a, b = float(a_str), float(b_str)
except ValueError:
print("輸入格式錯誤,請重新輸入,例如:3 + 5")
continue
result = calculator(a, op, b)
print(f"結果:{result}")
請撰寫一個程式,讓使用者輸入一個秒數,換算成「時 分 秒」格式輸出,例如輸入 3725 秒,輸出「1 時 2 分 5 秒」。
先用整數除法 // 3600 算出小時,用 % 3600 拿到扣掉小時後剩下的秒數;再對剩下的秒數做一次同樣的 // 60 與 % 60,分別算出分鐘與秒數。
# 秒數轉換成「時 分 秒」
total_seconds = int(input("請輸入秒數:"))
hours = total_seconds // 3600
remaining = total_seconds % 3600
minutes = remaining // 60
seconds = remaining % 60
print(f"{hours} 時 {minutes} 分 {seconds} 秒")
設計一個 BankAccount 類別:餘額用 private 欄位包起來,提供 Deposit(存款)與 Withdraw(提款,餘額不足要擋下)方法,以及唯讀的 Balance 屬性。練習封裝。
餘額欄位設 private,對外只開放方法與唯讀屬性;Withdraw 前先檢查金額是否超過餘額。
設計一個基底類別 Animal 含虛擬方法 MakeSound(),繼承出 Dog、Cat、Bird 各自 override 叫聲。用 List<Animal> 裝不同動物,foreach 呼叫 MakeSound() 觀察多型。
基底方法用 virtual、子類別用 override;把子類別物件放進 List<Animal> 就能展示多型。
拿你 ch13 完成的三層版庫存專案,重構成 MVP + Repository:DbHelper 改成 IProductRepository/ProductRepository、MainForm 實作 IProductView 只負責顯示與轉發事件、CRUD 邏輯全搬進 ProductPresenter、最後在 Program.cs 組裝。挑戰:再寫一個 InMemoryProductRepository 餵假資料,證明「換得掉資料來源」。功能不變,只練架構。
記住方向:畫面 raise 事件通知 Presenter,Presenter 呼叫 _view 的方法叫畫面做事;MainForm 裡不准出現 if 判斷或 DbHelper。組裝忘了 new Presenter 的話按鈕會沒反應(沒人訂事件)。
使用 HTML5 語意標籤建立一個個人介紹頁面,包含 header(姓名 + 職稱)、nav(頁內錨點)、main(自我介紹、技能、作品)、footer(聯絡方式)。
使用 <section> 區分不同內容區塊,<a href="#skills"> 建立頁內錨點導覽。
用 CSS Flexbox 實作:(1) 水平導覽列(左邊 Logo、右邊選項、最右邊按鈕);(2) 3 欄等寬卡片,卡片高度相同,內容靠上,按鈕靠底部。
導覽列用 space-between + align-items: center,卡片用 flex-direction: column 讓按鈕靠底。
建立 ProfileCard 元件,Props 包含姓名、職稱、技能列表、頭像 URL。技能列表用 map 渲染,加入 isOnline 布林 prop 顯示線上/離線狀態。
用 conditional rendering:{isOnline && <span>🟢</span>} 或三元運算子。
不使用迴圈,只用 NumPy 操作:建立一個 5×5 的隨機整數矩陣(0-100),計算每列平均、每欄最大值、標準化成 0-1 之間的值。
用 np.random.randint(),axis 參數控制方向,(x - x.min()) / (x.max() - x.min()) 標準化。
import numpy as np
# 固定亂數種子,方便重現結果(可移除)
np.random.seed(42)
# 建立 5x5、範圍 0~100 的隨機整數矩陣
matrix = np.random.randint(0, 101, size=(5, 5))
print("原始矩陣:")
print(matrix)
# 每「列」平均:axis=1 表示沿著欄方向計算(每一列得到一個值)
row_means = matrix.mean(axis=1)
print("\n每列平均:")
print(row_means)
# 每「欄」最大值:axis=0 表示沿著列方向計算(每一欄得到一個值)
col_max = matrix.max(axis=0)
print("\n每欄最大值:")
print(col_max)
# 標準化成 0~1 之間:(x - 最小值) / (最大值 - 最小值)
normalized = (matrix - matrix.min()) / (matrix.max() - matrix.min())
print("\n標準化結果:")
print(normalized)
撰寫一個函式 check_urls(urls),接受一個網址列表,回傳每個網址的 HTTP 狀態碼字典。需要處理網路錯誤與逾時。
使用 requests.get(url, timeout=5) 並包裹在 try/except 中。
import requests
def check_urls(urls):
"""接受網址列表,回傳 {網址: 狀態碼或錯誤訊息} 字典"""
results = {}
for url in urls:
try:
# timeout=5 秒,避免網站沒回應導致程式卡住
response = requests.get(url, timeout=5)
results[url] = response.status_code
except requests.exceptions.Timeout:
results[url] = "逾時"
except requests.exceptions.RequestException as e:
# 涵蓋連線錯誤、DNS 解析失敗等其他網路例外
results[url] = f"錯誤:{e}"
return results
if __name__ == "__main__":
urls = [
"https://www.python.org",
"https://www.google.com",
"https://this-domain-does-not-exist-abc123.com",
]
status_map = check_urls(urls)
for url, status in status_map.items():
print(f"{url} -> {status}")
程式隨機產生 1~100 的數字,讓使用者反覆猜,每次提示「太大/太小」,猜中就結束並顯示共猜了幾次。練習 while 迴圈與 if 條件判斷。
用 Random 產生答案,while (true) 迴圈搭配 break 跳出;用一個計數變數累加猜的次數。
爬取 PTT 某個版(如 Python 版)的最新 20 篇文章標題與作者,並存成 CSV 檔案。需要處理已刪除文章的情況。
注意 PTT 需要設定 Cookie 才能存取 18+ 版面,可以先用 Python 版練習。
import csv
import requests
from bs4 import BeautifulSoup
BOARD_URL = "https://www.ptt.cc/bbs/Python/index.html"
# PTT 會檢查是否已通過 18 歲同意頁,設定 cookie 避免被導去同意頁
COOKIES = {"over18": "1"}
def fetch_articles(url):
"""爬取單一頁面的文章標題與作者,回傳 list of dict"""
resp = requests.get(url, cookies=COOKIES, timeout=5)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
articles = []
for entry in soup.select("div.r-ent"):
title_tag = entry.select_one("div.title a")
# 已刪除的文章沒有 <a> 標籤,title 會顯示「本文已被刪除」
if title_tag is None:
title = "(已刪除)"
author = "(未知)"
else:
title = title_tag.text.strip()
author_tag = entry.select_one("div.meta div.author")
author = author_tag.text.strip() if author_tag else "(未知)"
articles.append({"title": title, "author": author})
return articles
def main():
articles = fetch_articles(BOARD_URL)[:20]
with open("ptt_python_board.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=["title", "author"])
writer.writeheader()
writer.writerows(articles)
print(f"共爬取 {len(articles)} 篇文章,已存成 ptt_python_board.csv")
if __name__ == "__main__":
main()
爬取某電商網站商品列表的前 5 頁,收集商品名稱、價格、評分,計算最高/最低/平均價格,並輸出統計報告。
分析 URL 的換頁規律,加入隨機延遲,用 pandas DataFrame 管理資料並計算統計值。
import time
import random
import requests
import pandas as pd
from bs4 import BeautifulSoup
# 假設商品列表頁的換頁規律是 ?page=N(依實際網站調整)
BASE_URL = "https://example-shop.com/products?page={}"
HEADERS = {"User-Agent": "Mozilla/5.0"}
def fetch_page(page: int):
"""爬取單一頁的商品資料,回傳 list of dict"""
url = BASE_URL.format(page)
resp = requests.get(url, headers=HEADERS, timeout=5)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
products = []
for item in soup.select(".product-item"):
name_tag = item.select_one(".product-name")
price_tag = item.select_one(".product-price")
rating_tag = item.select_one(".product-rating")
if not (name_tag and price_tag):
continue
# 價格文字可能含「$」「,」等符號,需清理後轉數字
price_text = price_tag.text.strip().replace("$", "").replace(",", "")
products.append({
"name": name_tag.text.strip(),
"price": float(price_text),
"rating": float(rating_tag.text.strip()) if rating_tag else None,
})
return products
def main():
all_products = []
for page in range(1, 6): # 前 5 頁
all_products.extend(fetch_page(page))
# 加入隨機延遲,避免對伺服器造成負擔或被判定為機器人
time.sleep(random.uniform(1, 2))
df = pd.DataFrame(all_products)
print("=== 商品統計報告 ===")
print(f"總商品數:{len(df)}")
print(f"最高價格:{df['price'].max():.0f}")
print(f"最低價格:{df['price'].min():.0f}")
print(f"平均價格:{df['price'].mean():.2f}")
df.to_csv("products_report.csv", index=False, encoding="utf-8-sig")
print("已輸出 products_report.csv")
if __name__ == "__main__":
main()
給定一份包含缺失值與重複資料的學生成績 CSV,完成清洗:移除重複、填補缺失分數(用班級平均)、將文字型態的分數轉換成數字型態。
用 df.duplicated() 找重複,df.isnull() 找缺失,groupby + transform 計算分組平均。
import pandas as pd
# 讀取原始資料(假設欄位有 name, class, score,score 可能是字串或缺失值 NaN)
df = pd.read_csv("students_raw.csv")
# 1. 將分數欄位統一轉換成數字型態(無法轉換的值會變成 NaN,方便後續補值)
df["score"] = pd.to_numeric(df["score"], errors="coerce")
# 2. 移除完全重複的資料列
df = df.drop_duplicates()
# 3. 用「班級平均分數」填補缺失分數
# 先計算每個班級的平均分數,再對應填回缺失值
class_avg = df.groupby("class")["score"].transform("mean")
df["score"] = df["score"].fillna(class_avg)
# 4. 四捨五入到小數點後 1 位,讓資料乾淨
df["score"] = df["score"].round(1)
df.to_csv("students_cleaned.csv", index=False, encoding="utf-8-sig")
print("清洗完成,已輸出 students_cleaned.csv")
print(df)
載入範例銷售資料,繪製:(1) 各月份銷售額折線圖 (2) 各地區銷售佔比圓餅圖 (3) 各商品類別長條圖。所有圖表存成一個 PDF 報告。
用 matplotlib.backends.backend_pdf.PdfPages 將多張圖儲存成一個 PDF 檔案。
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
# 讓中文字型正常顯示(Windows 可用「Microsoft JhengHei」,Mac 可用「PingFang TC」)
plt.rcParams["font.sans-serif"] = ["Microsoft JhengHei"]
plt.rcParams["axes.unicode_minus"] = False
# 讀取範例銷售資料,欄位假設為:month, region, category, amount
df = pd.read_csv("sales_data.csv")
with PdfPages("sales_report.pdf") as pdf:
# (1) 各月份銷售額折線圖
monthly = df.groupby("month")["amount"].sum().sort_index()
fig1, ax1 = plt.subplots(figsize=(8, 5))
ax1.plot(monthly.index, monthly.values, marker="o")
ax1.set_title("各月份銷售額趨勢")
ax1.set_xlabel("月份")
ax1.set_ylabel("銷售額")
pdf.savefig(fig1)
plt.close(fig1)
# (2) 各地區銷售佔比圓餅圖
region_sales = df.groupby("region")["amount"].sum()
fig2, ax2 = plt.subplots(figsize=(6, 6))
ax2.pie(region_sales.values, labels=region_sales.index, autopct="%1.1f%%")
ax2.set_title("各地區銷售佔比")
pdf.savefig(fig2)
plt.close(fig2)
# (3) 各商品類別長條圖
category_sales = df.groupby("category")["amount"].sum().sort_values(ascending=False)
fig3, ax3 = plt.subplots(figsize=(8, 5))
ax3.bar(category_sales.index, category_sales.values)
ax3.set_title("各商品類別銷售額")
ax3.set_xlabel("商品類別")
ax3.set_ylabel("銷售額")
pdf.savefig(fig3)
plt.close(fig3)
print("報告已產出:sales_report.pdf")
把一組學生成績放進 List<int>,計算平均分、最高分、最低分,並由高到低排序印出。練習集合的走訪、新增與排序。
善用 List 的 Count、以及排序方法;平均要注意整數除法會被截斷,先轉成 double。
用 SQLite 為「商品」建表(編號、名稱、價格、庫存量),實作完整的新增、修改、刪除、查詢,並在讀檔/連資料庫的地方加上 try/catch。這是課程貫穿主線的第三次 CRUD 練習。
把資料庫操作集中到一個 DbHelper 類別;每個操作用參數化 SQL,避免字串拼接。
綜合運用 HTML、Flexbox、CSS Grid 與 Media Query,完成一個響應式課程網站首頁:桌機 3 欄卡片、平板 2 欄、手機單欄,導覽列手機版折疊。
用 CSS Grid 搭配 auto-fill 或固定欄數 + Media Query 切換,用 checkbox hack 做折疊選單。