Home
Explore Uedu
Student Console
Register as Member/Login
(2) In future presentations of the research findings, in addition to the course project website and public presentations, your real name and personal information will not appear in this research report. If you are interested in the research results, we can provide you with an executive summary after the study is completed.
問卷中心
Teacher Console
Course Setup
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

0

Local AI

--

CISOSE26 本地 AI UG26
政治大學 AQI 18 29°C

AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

變數、型別與運算

Python 變數、型別與運算:從一張收據開始

用一支合購分帳小程式,帶你掌握變數賦值、動態型別、四大基本型別、算術與邏輯運算子、型別轉換與整數除法,最後深入 Python 萬物皆物件的記憶體模型。

從一張收據開始:讓程式記住每一筆數字

想像你正在寫一支小程式,幫同學算這學期合購教科書的分帳。三個人合買一本 720 元的書、運費 60 元,要算出每人該付多少、找零幾元。你大可以把 720、60、3 這些數字直接散落在算式裡,但只要書價一改,你就得在整段程式裡到處翻找、逐一修改——這正是「變數」要解決的問題。

變數讓程式可以「記住」一個值,並用一個有意義的名字稱呼它。改一處,全程式跟著變。這一篇,我們就從變數出發,一路走到型別、運算子與型別轉換,把 Python 處理資料的基本骨架建立起來。建議你打開一個 Python 直譯器(在終端機輸入 pythonpython3),每讀到一段程式就親手敲一次,感受會完全不同。

變數、型別與運算概念示意圖

變數與賦值:名字綁到值

在 Python 裡,建立變數就是用等號 = 把一個值「賦」給一個名字:

book_price = 720     # 書價
shipping = 60        # 運費
people = 3           # 分攤人數

total = book_price + shipping
per_person = total // people   # 每人付多少(整數除法,稍後會解釋)

print(total)        # 輸出:780
print(per_person)   # 輸出:260

這裡有幾個值得注意的地方。等號 = 不是數學上的「相等」,而是「賦值」這個動作:把右邊算出的值,綁到左邊的名字上。所以 total = book_price + shipping 是先算出右邊的 780,再把它綁給 total

正因為如此,下面這種寫法在數學上荒謬,在程式裡卻完全合理:

count = 10
count = count + 1   # 先取出舊的 count(10)加 1,再綁回 count
print(count)        # 輸出:11

變數命名請遵循 Python 的慣例(PEP 8 精神):使用小寫加底線的 snake_case,名字要能說明用途。per_personppx 清楚得多,未來的你會感謝現在的你。

# 推薦:見名知意
student_count = 42

# 反模式:意義不明,請避免
sc = 42
x = 42

動態型別:值有型別,名字沒有

C、Java 這類語言要求你先宣告變數的型別(int x = 5;),之後 x 就只能裝整數。Python 不是這樣——它是動態型別(dynamically typed):型別屬於「值」,不屬於「名字」。同一個名字,前一刻綁整數、下一刻綁字串,完全合法:

data = 100      # 此刻 data 綁的是整數
data = "hello"  # 現在 data 改綁字串,沒問題
data = 3.14     # 再改綁浮點數,也沒問題

這帶來彈性,但也要求你心裡清楚每個變數「現在」裝的是什麼。想知道某個值的型別,用內建函式 type()

print(type(100))       # 輸出:<class 'int'>
print(type(3.14))      # 輸出:<class 'float'>
print(type("hello"))   # 輸出:<class 'str'>
print(type(True))      # 輸出:<class 'bool'>

四種最基本的型別

剛起步時,你會反覆遇到四種內建型別:整數、浮點數、字串、布林。

整數 int:沒有小數點的數,Python 的整數可以無限大(只受記憶體限制),不像許多語言有 32 位元上限:

big = 2 ** 100   # 2 的 100 次方
print(big)       # 輸出:1267650600228229401496703205376
print(type(big)) # 輸出:<class 'int'>

浮點數 float:帶小數點的數。只要式子裡出現小數,結果通常就是浮點數:

height = 1.72
print(type(height))     # 輸出:<class 'float'>
print(type(10 / 3))     # 輸出:<class 'float'>(除法 / 永遠回傳 float)

字串 str:用單引號或雙引號包起來的文字。兩者效果相同,挑一種風格保持一致即可:

name = "陳同學"
greeting = '你好'
full = greeting + "," + name   # 用 + 串接字串
print(full)                     # 輸出:你好,陳同學

布林 bool:只有 TrueFalse 兩個值(注意首字母大寫),用來表達「成立與否」。它其實是整數的特例,True 等於 1、False 等於 0:

is_passed = True
print(is_passed + 1)   # 輸出:2(True 當作 1 參與運算)

運算子:算術、比較、邏輯

算術運算子做數學計算:

print(7 + 3)    # 輸出:10  加
print(7 - 3)    # 輸出:4   減
print(7 * 3)    # 輸出:21  乘
print(7 / 3)    # 輸出:2.3333333333333335  除(結果是 float)
print(7 ** 2)   # 輸出:49  次方

比較運算子問一個是非題,結果一定是布林值:

print(5 > 3)    # 輸出:True
print(5 == 5)   # 輸出:True   注意:判斷相等用 ==,不是 =
print(5 != 3)   # 輸出:True   != 是「不等於」
print(5 <= 4)   # 輸出:False

請特別記住:= 是賦值,== 才是比較相等。把兩者搞混是初學者最常見的錯誤之一。

邏輯運算子 andornot 把布林值組合起來:

age = 20
has_id = True

print(age >= 18 and has_id)   # 輸出:True   兩者都成立才 True
print(age < 18 or has_id)     # 輸出:True   只要一個成立就 True
print(not has_id)             # 輸出:False  反轉真假

當多種運算子混用時,優先順序是:算術 → 比較 → 邏輯。不確定時,用括號把意圖寫清楚,既不會算錯,也讓讀者一眼看懂:

score = 85
result = (score >= 60) and (score <= 100)
print(result)   # 輸出:True

型別轉換:在型別之間搬運

不同型別有時需要互相轉換。Python 提供同名的轉換函式 int()float()str()bool()

最常見的場景是處理使用者輸入。input() 拿到的永遠是字串,要拿來計算就得先轉成數字:

text = "42"
number = int(text)       # 字串轉整數
print(number + 8)        # 輸出:50

price = float("3.99")    # 字串轉浮點數
print(price)             # 輸出:3.99

count = 7
message = "共 " + str(count) + " 人"   # 數字轉字串才能串接
print(message)                         # 輸出:共 7 人

轉換不是萬能的。把一個不像數字的字串硬轉成 int 會直接報錯:

int("abc")   # ValueError: invalid literal for int() with base 10: 'abc'

int() 把浮點數轉整數時是直接捨去小數(往零的方向截斷),不是四捨五入,這點容易踩雷:

print(int(3.9))    # 輸出:3   小數被捨去,不是 4
print(int(-2.7))   # 輸出:-2  往零截斷

bool() 的轉換規則也值得認識:00.0、空字串 ""None 都會轉成 False,其餘多半是 True

print(bool(0))     # 輸出:False
print(bool(""))    # 輸出:False
print(bool(42))    # 輸出:True
print(bool("a"))   # 輸出:True

None:明確表示「沒有值」

有時你需要表達「這裡目前還沒有值」,而不是 0 或空字串。Python 為此提供一個特殊物件 None,它自成一個型別 NoneType

answer = None
print(answer)         # 輸出:None
print(type(answer))   # 輸出:<class 'NoneType'>

None 常用來當變數的初始狀態,或表示「函式沒有回傳任何東西」。判斷一個變數是不是 None,慣例是用 is,而不是 ==

selected = None

# 推薦寫法
if selected is None:
    print("尚未選擇")   # 輸出:尚未選擇

# 反模式:能動但不符慣例,請避免
# if selected == None:

整數除法與取餘:分得乾乾淨淨

回到開頭的分帳問題。一般除法 / 會給你帶小數的結果,但「三個人分十個雞蛋」這種問題,你要的是「每人幾個、剩幾個」,這就要用整數除法 // 和取餘 %

eggs = 10
people = 3

print(eggs // people)   # 輸出:3   每人 3 個(整數除法,捨去小數)
print(eggs % people)    # 輸出:1   剩下 1 個(餘數)

這兩個運算子用途極廣。判斷奇偶、做進位、把秒數拆成分與秒,都靠它們:

seconds = 200
print(seconds // 60, "分", seconds % 60, "秒")   # 輸出:3 分 20 秒

n = 17
print(n % 2 == 0)   # 輸出:False(餘數不為 0,所以是奇數)

動手寫一段:合購分帳機

把這一篇學到的東西組合起來,寫一支完整的分帳小程式:

# 合購分帳機
book_price = 720      # 書價
shipping = 60         # 運費
people = 3            # 分攤人數

total = book_price + shipping        # 總金額
per_person = total // people         # 每人應付(整數元)
remainder = total % people           # 無法整除的零頭

# 組出可讀的報告(數字要轉成字串才能串接)
report = (
    "總金額:" + str(total) + " 元\n"
    + "每人應付:" + str(per_person) + " 元\n"
    + "零頭:" + str(remainder) + " 元(由發起人吸收)"
)
print(report)

# 預期輸出:
# 總金額:780 元
# 每人應付:260 元
# 零頭:0 元(由發起人吸收)

試著把 book_price 改成 700,再跑一次,看看 per_personremainder 怎麼變化。你會發現:因為用變數記住了書價,整支程式只要改那一行,其餘自動跟著更新——這正是開頭那張收據想說明的價值。

重點回顧:初學者最常踩的雷

  • === 不一樣= 是賦值(把值綁給名字),== 是比較是否相等。在 if 條件裡誤用 = 是經典錯誤。
  • / 永遠回傳浮點數。即使 10 / 2 也會得到 5.0 而非 5。需要整數結果就用 //
  • int() 是截斷不是四捨五入int(3.9) 得到 3。要四捨五入請改用 round()
  • 數字與字串不能直接相加"共 " + 7 會報 TypeError,必須先 str(7) 轉成字串,或改用 f-string。
  • 判斷 Noneis None,而不是 == None,這是 Python 社群的明確慣例。

深入探討(研究所視角):萬物皆物件

前面我們把變數說成「名字綁到值」,現在把這句話講透。在 Python 裡,萬物皆物件(everything is an object)——整數、字串、布林、函式、甚至型別本身,全都是物件。每個物件在記憶體中有三個固有屬性:身分(identity)、型別(type)、值(value)。身分可以用內建函式 id() 取得,它在 CPython 中對應到該物件的記憶體位址:

a = 256
print(id(a), type(a))   # 例如:140703... <class 'int'>

賦值 a = 256 真正發生的事,是建立(或取得)一個值為 256 的整數物件,再讓名字 a 指向它。所以變數不是「裝值的盒子」,而比較像是「貼在物件上的標籤」。多個名字可以貼在同一個物件上:

x = [1, 2, 3]
y = x            # y 與 x 指向「同一個」串列物件
print(x is y)    # 輸出:True(is 比較的是身分,不是值)
print(id(x) == id(y))   # 輸出:True

這就帶出 Python 最重要、也最容易出錯的分野:可變(mutable)與不可變(immutable)

intfloatstrbooltupleNone 都是不可變的。你無法改變一個整數物件本身;所謂「修改」其實是讓名字改指到另一個新物件:

n = 10
print(id(n))     # 假設是位址 A
n = n + 1
print(id(n))     # 換成位址 B——n 指向了一個全新的物件 11,原本的 10 沒被改動

listdictset可變的。你可以原地修改物件內容,身分(id)不變:

nums = [1, 2, 3]
print(id(nums))     # 假設是位址 C
nums.append(4)
print(nums)         # 輸出:[1, 2, 3, 4]
print(id(nums))     # 仍是位址 C——同一個物件,只是內容變了

可變性的陷阱在於共享參考(shared reference)。承接前面的例子,因為 y = x 讓兩個名字指向同一個串列,透過任一個名字修改,另一個也會「看到」變化:

x = [1, 2, 3]
y = x
y.append(99)
print(x)   # 輸出:[1, 2, 3, 99]——明明只動了 y,x 也變了

若你要的是一份獨立副本,必須明確複製,例如 y = x[:]y = x.copy()。對不可變物件就沒有這個煩惱,因為它根本無法被原地修改。

最後一個常讓人困惑的細節:CPython 會快取小整數(通常是 −5 到 256)與部分短字串,讓相同的值共用同一個物件以節省記憶體。這導致 is 在小數字上「看似」可用:

a = 256
b = 256
print(a is b)   # 輸出:True(256 在快取範圍內,共用物件)

c = 257
d = 257
print(c is d)   # 輸出:可能 False(超出快取範圍,是兩個不同物件)

這正是為什麼比較「值是否相等」要用 ==,比較「是否為同一物件」才用 is——is None 之所以正確,恰恰因為整個程式裡 None 永遠是獨一無二的同一個物件。理解了物件模型,你對賦值、參考與可變性的直覺就會從「會用」升級為「知其所以然」,這在日後處理函式參數傳遞、預設可變參數等進階陷阱時,會是你最可靠的判斷依據。

AI 共讀助教正在陪你讀:Python 變數、型別與運算:從一張收據開始
嗨!我是這篇文章的共讀助教,只根據〈Python 變數、型別與運算:從一張收據開始〉的內容回答。可以問我「解釋某段」「舉個例子」「出題考我」,或反白文中段落後點下方「解釋選取段落」。