Python 入門與環境:從第一支程式到直譯器原理
從一句問候出發,理解為何 Python 成為資料科學與 AI 的主力語言,並掌握直譯器、REPL、縮排語法與「變數即名牌」的核心直覺。
從一句問候開始:你的第一支 Python 程式
想像你坐在電腦前,想做一件很小的事:讓電腦對你說「哈囉」。在許多語言裡,這件事要先宣告型別、寫一個 main 函式、用大括號包住程式區塊,最後還得編譯。而在 Python 裡,你只需要打一行字:
print("哈囉,世界!")
按下執行,螢幕就回你:
哈囉,世界!
沒有樣板、沒有編譯指令、沒有分號。這種「想到什麼就寫什麼」的直接感,正是 Python 成為資料科學與人工智慧(AI)主力語言的起點。這篇文章會帶你從零認識 Python 的環境與語法直覺,並動手寫出能跑的程式。準備好你的鍵盤,我們開始。

為什麼選 Python
語言這麼多,為什麼初學程式、做研究、進產業,大家都先學 Python?三個理由值得你記住。
第一,可讀性。 Python 的設計哲學寫在它的彩蛋裡,你可以親自執行:
import this
它會印出《The Zen of Python》,其中最重要的兩句是「Readable counts.(可讀性很重要)」與「There should be one obvious way to do it.(應該有一種顯而易見的做法)」。Python 強制用縮排來表達程式結構,逼著每個人寫出排版一致的程式碼。你讀別人的 Python,往往像讀英文句子。
第二,生態系(ecosystem)。 Python 之所以強,不只是語言本身,而是它背後龐大的套件(package)生態。做數值運算有 NumPy、做資料分析有 pandas、畫圖有 Matplotlib、機器學習有 scikit-learn、深度學習有 PyTorch 與 TensorFlow。這些工具已經被全世界的研究者與工程師打磨多年,你站在巨人的肩膀上。
# 一行安裝,全世界的數值運算工具就到手
# 在終端機(不是 Python 裡)執行:
# pip install numpy
import numpy as np
data = np.array([1, 2, 3, 4, 5])
print(data.mean())
# 輸出:3.0
第三,它是資料科學與 AI 的主力語言。 從學術論文的實驗程式、Kaggle 競賽,到 OpenAI、Google 的模型訓練流程,Python 幾乎是預設語言。學會它,等於拿到進入這個領域的通行證。
當然 Python 不是萬靈丹——它執行速度比 C 或 Rust 慢(後面深入段會解釋為什麼),不適合寫對效能極度敏感的底層系統。但對於「快速把想法變成可運作的程式」這件事,很少有語言比它更稱手。
直譯器與 REPL:跟電腦對話
要理解 Python 怎麼運作,先認識「直譯器(interpreter)」這個角色。
你寫的 Python 程式碼是給人看的文字。電腦看不懂,它只懂機器碼。中間需要一個翻譯官,把你的程式碼一行一行讀進來、翻譯、執行——這個翻譯官就是 Python 直譯器。最常見的實作叫 CPython,是用 C 語言寫成的(深入段會細談)。
直譯器最迷人的用法是 REPL,全名 Read-Eval-Print Loop(讀取-求值-印出-循環)。在終端機輸入 python 就會進入:
>>> 3 + 4
7
>>> name = "同學"
>>> "哈囉," + name
'哈囉,同學'
>>> len("Python")
6
每打一行,直譯器立刻讀取你的輸入、求值、印出結果,然後等你下一行。這就像跟電腦即時對話。當你不確定某個語法怎麼用、想驗證一個小想法時,REPL 是最快的實驗場。鼓勵你現在就打開它玩玩看。
小提醒:REPL 裡的
>>>是提示符號,是直譯器印給你的,你不需要自己打。
縮排即語法:空白有意義
如果你學過 C、Java 或 JavaScript,會習慣用大括號 { } 來框出程式區塊。Python 把這套全部拿掉,改用縮排來表達「誰屬於誰」。
score = 85
if score >= 60:
print("及格")
print("恭喜")
print("評分結束")
注意 if 底下那兩行 print 各往右縮了四格空白,它們屬於 if 的區塊;而最後一行 print("評分結束") 沒有縮排,所以無論及不及格都會執行。輸出是:
及格
恭喜
評分結束
縮排在 Python 裡不是排版美觀,而是語法本身。縮排錯了,程式就跑不動,或行為完全不同。看看這個對比:
# 反模式:縮排不一致會直接報錯
if score >= 60:
print("及格")
print("恭喜") # 多縮了兩格 → IndentationError
慣例上,Python 社群的風格規範 PEP 8 建議用四個空白鍵縮排,不要用 Tab,而且全檔統一。大多數編輯器可以設定「按 Tab 自動轉成四個空白」,請務必開啟。混用 Tab 與空白是初學者最常見、也最難察覺的錯誤來源。
print 與註解:輸出與筆記
print() 是你最早、也最常用的工具,它把東西印到螢幕上。它很聰明,可以一次印多個值,用逗號隔開會自動補空白:
print("姓名:", "小明", "年齡:", 20)
# 輸出:姓名: 小明 年齡: 20
它也接受幾個好用的參數。sep 控制分隔符號,end 控制結尾(預設是換行 \n):
print("2026", "06", "14", sep="-")
# 輸出:2026-06-14
print("沒有換行", end="")
print("會接在同一行")
# 輸出:沒有換行會接在同一行
註解(comment) 是寫給人看、直譯器會略過的文字。Python 用 # 開頭表示單行註解:
# 這是一行註解,直譯器不會執行
radius = 5 # 也可以寫在程式碼後面,說明這個變數的意義
area = 3.14159 * radius ** 2 # ** 是次方運算
註解的目的是解釋「為什麼這樣做」,而不是複述程式碼字面意思。好的註解像旁白,幫未來的你(或同學)讀懂思路。反模式是寫一堆 x = x + 1 # x 加 1 這種廢話註解,那只是噪音。
變數即名牌:名字貼在物件上
很多教材把變數(variable)比喻成「裝東西的盒子」,這個比喻在 Python 裡其實會誤導你。更準確的心智模型是:變數是一張名牌(name tag),貼在某個物件(object)上。
x = 10
y = x # y 也貼到同一個 10 上
x = 20 # x 改貼到新的 20,y 不受影響
print(x, y)
# 輸出:20 10
當你寫 y = x,並不是把 10 複製一份給 y,而是讓 y 這張名牌也指向 x 所指的那個 10。之後 x = 20 是把 x 撕下來、改貼到另一個物件 20,y 仍然貼在原本的 10。
這個觀念在處理可變(mutable)物件如串列(list)時格外重要:
a = [1, 2, 3]
b = a # b 和 a 是同一張清單的兩張名牌
b.append(4)
print(a)
# 輸出:[1, 2, 3, 4] ← a 也變了!
因為 a 和 b 貼在同一個串列上,透過 b 修改內容,a 看到的也是修改後的結果。如果你真的想要一份獨立的副本,要明確複製:
a = [1, 2, 3]
b = a.copy() # b 貼在一張新的、內容相同的清單上
b.append(4)
print(a, b)
# 輸出:[1, 2, 3] [1, 2, 3, 4]
記住「名牌貼在物件上」這個模型,你會少踩很多坑。
Python 是動態型別(dynamically typed):你不需要事先宣告變數是整數還是字串,名牌可以隨時改貼到不同型別的物件上。
v = 42 # 現在 v 貼在整數上
print(type(v)) # 輸出:<class 'int'>
v = "你好" # 同一個名字改貼到字串上,完全合法
print(type(v)) # 輸出:<class 'str'>
這很方便,但也有代價——後面深入段會談這份自由背後的成本。
動手寫一段:BMI 計算機
把前面學到的東西組起來,寫一支完整、可執行的小程式。它請使用者輸入身高體重,算出 BMI(身體質量指數)並判斷區間。
# bmi.py — 簡易 BMI 計算機
# input() 讀取使用者輸入,回傳的一律是字串,要轉成數字
height_cm = float(input("請輸入身高(公分):"))
weight_kg = float(input("請輸入體重(公斤):"))
# 公式:BMI = 體重(kg) / 身高(m)^2
height_m = height_cm / 100
bmi = weight_kg / (height_m ** 2)
# round() 四捨五入到小數點後一位
print("你的 BMI 是:", round(bmi, 1))
if bmi < 18.5:
print("體重過輕")
elif bmi < 24:
print("正常範圍")
else:
print("體重過重")
假設使用者輸入身高 170、體重 65,預期輸出:
請輸入身高(公分):170
請輸入體重(公斤):65
你的 BMI 是: 22.5
體重過重
這支小程式用到了輸入轉型、算術運算、if / elif / else 多重判斷與輸出,是把今天所有概念串起來的好練習。鼓勵你改改看:加一個「過重再細分」的條件,或把判斷包成一個函式。
常見錯誤與重點回顧
初學 Python,這幾個雷請特別留意:
- 縮排混用 Tab 與空白:看起來對齊,直譯器卻報
IndentationError或TabError。請設定編輯器一律用四個空白,全檔統一。 - 以為變數是盒子:
b = a對串列等可變物件來說,兩個名字指向同一份資料。要獨立副本請用.copy()或切片a[:]。 - input() 回傳的是字串:
input()永遠給你字串,要做數學運算前記得用int()或float()轉型,否則"5" + "3"會得到"53"而不是8。 - = 與 == 搞混:
=是賦值(把名牌貼上去),==是比較(問兩邊相不相等)。寫if x = 5會直接語法錯誤。 - 中文全形符號混入程式碼:把程式裡的括號
()或引號""打成全形()「」,直譯器會報SyntaxError。註解和字串內容可以放中文,但語法符號必須是半形。
深入探討(研究所視角)
前面說 Python 是「直譯語言」,但這個說法其實過於簡化。要真正理解 Python 的執行模型與效能特性,得拆開 CPython 的內部流程。
CPython 的直譯流程:原始碼不是直接被「逐行翻譯」。 當你執行一支 .py 檔,CPython 並不是一行一行邊讀邊翻成機器碼。它分成兩個階段。第一階段是編譯(compile):CPython 把原始碼先解析成抽象語法樹(AST, Abstract Syntax Tree),再編譯成一種中介表示——位元碼(bytecode)。位元碼是一組與平台無關的低階指令,不是 CPU 的機器碼,而是給 Python 虛擬機看的。第二階段才是執行:由 Python 虛擬機(PVM, Python Virtual Machine) 這個巨大的求值迴圈逐條讀取位元碼指令並執行。
你可以親眼看到位元碼:
import dis
def add(a, b):
return a + b
dis.dis(add)
# 輸出(節錄,版本不同略有差異):
# LOAD_FAST a
# LOAD_FAST b
# BINARY_OP + (add)
# RETURN_VALUE
LOAD_FAST、BINARY_OP 這些就是位元碼指令,PVM 一條條照著做。
.pyc 檔的意義。 當你 import 一個模組時,CPython 會把編譯好的位元碼快取成 .pyc 檔,存在 __pycache__/ 資料夾裡。下次再 import,只要原始碼沒改,就直接載入 .pyc,跳過重新編譯,加快啟動。注意:這只是省下編譯步驟,不會讓執行本身變快——因為真正的瓶頸在 PVM 逐條解釋位元碼這一段。這也解釋了為何你直接執行的主程式(python main.py)不會產生 .pyc,但被它 import 的模組會。
動態型別的代價。 回到前面 v = 42 後又 v = "你好" 的例子。這份自由不是免費的。因為型別在執行期才能確定,PVM 每執行一個運算(例如 a + b)都必須在當下檢查 a 和 b 到底是什麼型別、有沒有定義 +、該呼叫哪個方法。在靜態型別的編譯語言(如 C)裡,型別在編譯期就鎖定,a + b 可以直接編成一兩條 CPU 加法指令;而在 CPython 裡,同樣一個加法要經過多層型別查詢與方法分派(dispatch)。再加上 Python 的所有值都是堆積(heap)上的物件、帶著參考計數與型別資訊,這些都讓動態語言天生比靜態編譯語言慢上一個數量級。這就是 Python「慢」的根源。
直譯 vs 編譯,是光譜不是二分。 嚴格來說 CPython 是「先編譯成位元碼、再解釋執行」的混合模式。純編譯語言(C)一次把整支程式翻成機器碼再交給 CPU 跑,執行快但缺少互動性、跨平台需重編。純解釋(早期的 shell)逐行翻譯,最慢但最靈活。CPython 居中。而要突破 PVM 解釋的瓶頸,業界發展出即時編譯(JIT, Just-In-Time compilation)技術——例如 PyPy 在執行期把熱點程式碼動態編譯成機器碼,CPython 3.13 起也開始引入實驗性 JIT。理解了這條「原始碼 → AST → 位元碼 → PVM」的鏈條,你就能解釋為什麼 Python 開發快、執行慢,以及在做資料科學時,為什麼真正吃重的數值運算要交給用 C 寫成的 NumPy,而不是用純 Python 的迴圈硬算。