「為你自己學 Python」正式上架!

為你自己學 Python

「為你自己學 Python」一書已經正式出版,書本裡的內容全文可在網站上免費閱讀,但如果您覺得拿在手上閱讀比較有感覺,在天瓏書局也能購買紙本書:

雖然我曾經寫過五、六年的 Python 程式,也曾在社群教過一陣子的 Python 課,但要提筆寫書又是不同的故事了。這本書從開始寫書到定稿,大概花了我一年多的時間,除了把以前上課的教材做了一次大大的整理,同時順便更新教材的軟體版本(當年還是 Python 2.x 的時代)。不只這樣,有些我當年自認為的觀念或看法,隨著年紀也有不同的領悟,也趁這個機會校正我自己對 Python 的理解。

這本書以 Python 3.12 做為主要教學版本,內容涵蓋環境安裝及 Python 程式語法,包括各種常用資料型態、邏輯及流程判斷、迴圈、錯誤處理、函數、模組、物件導向程式設計、檔案處理等,並透過網站爬蟲程式抓取並分析資料。沒有太多華麗的技巧,只有最基礎的程式觀念,期望能夠讓讀者在學習 Python 的過程中,建立穩固且正確的基礎。

在撰寫過程中,我除了翻閱官方文件以及 PEP(Python Enhancement Proposal)之外,有些我搞不清楚原理而且文件裡沒特別提到的設計,我就直接去翻 Python 的 C 語言原始碼來驗證自己的想法。新手自學程式容易被不完全正確觀念的影響而不自知,因此在這本書中我力求呈現正確且精準的觀念。我希望這不僅是一本程式自學參考書,也能引導各位讀者掌握 Python 正確的觀念,試著建立自己的「單一真相來源(Single Source of Truth)」。

鐵人賽 - 為你自己讀 CPython 原始碼

鐵人賽 - 為你自己讀 CPython 原始碼

這次的 iThome 鐵人賽,我給自己選了一個有點硬的主題,就是閱讀 CPython 的原始碼。

今年也剛好在 PyCon Taiwan 有一場工作坊,主題是介紹如何閱讀 CPython 的原始碼,所以原本只是想藉著鐵人賽的活動,把工作坊的內容文字化做為補充資料,沒想到越寫越多,對我這個不懂 C 語言的人來說更是吃力。雖然現在有很多 AI 工具的輔助,但幾乎每篇文章得要一邊挖原始碼,一邊驗證我解讀的程式碼是不是正確的,每篇文章至少都得花三個小時以上的時間。

你是數字,我是數字,我們不一樣!

你是數字,我是數字,我們不一樣!

在 Python 裡的 id() 函數可以算出某個值或物件在 Python 世界裡的「編號」,如果有兩個值算出來的編號是一樣的,表示這兩個值不只相等,而且還是一顆物件。

那麼問題來了,我寫了一個程式叫做 hello.py,內容如下:

a = 100
b = 200

def hey():
  return 300

res1 = 300
res2 = 100 + 200
res3 = a + b
res4 = hey()

print(id(res1))
print(id(res2))
print(id(res3))
print(id(res4))

當我執行 python hello.py 的時候,最後四行印出來的 id,有一個跟其它三個是不一樣的,猜猜看是哪一個。

空虛的真

空虛的真

來一個我自己覺得滿有趣的 Python 程式問答題。

在 Python 裡,all() 這個函數可以接一個串列,串列裡的每一顆元素都成立的時候就會回傳 True,反之只要有一顆不成立,就會是 False,例如:

>>> all([True, True, True])
True
>>> all([True, False, True])
False

題目來了:

>>> all([])     # A
>>> all([[]])   # B
>>> all([[[]]]) # C

一堆中括號、小括號,眼睛都快看花了,在正式的專案千萬不要這樣整自己(或是你的同事)!大家猜猜看 A、B、C 的結果分別是什麼?

為你自己學 Python

為你自己學 Python

為你自己學 Python

https://pythonbook.cc/

TL;DR, 先說結論:

這是我最近寫的書「為你自己學 Python」,實體書 & 電子書正在編輯中,網站上的內容除另有標示外,將會以 CC BY-NC-SA 4.0 方式授權予公眾自由取用。

希望對想要學習 Python 程式語言的朋友有些幫助 :)

為什麼索引值從 0 開始算?

為什麼索引值從 0 開始算?

有沒有想過為什麼我們學的數學是從 1 開始算,但好像大部份比較主流的程式語言的陣列包括 Python 的串列,索引值卻是從 0 開始的?因為這是因為陣列的索引值並不是指向元素本身,比較像是記憶體位置的「偏移量」。

假設有一個陣列像這樣:

chars = ['a', 'b', 'c', 'd']

當我們說「變數 chars 指向 ['a', 'b', 'c', 'd'] 陣列」的時候,並不是 chars 這個變數直接指向這一整個陣列,而是 chars 變數指向這個陣列的「起始位置」,更精準的說是記憶體位置。陣列在記憶體裡的位置跟門牌號碼一樣都是連號的,假設這個陣列的起始記憶體位置是 1450,然後每個元素所佔的位置或說格子的大小我就先隨便假設是 8(先不管單位跟以及為什麼是 8)。大概示意圖如下:

為什麼索引值從 0 開始

這樣的話,你認為要怎麼取得第一個元素的 a 字元?不就是指向 1450 的位置就拿到了嗎?(你也可以說是從 14501458 這一塊空間)。

我們現在知道怎麼拿第一個元素了,接著要怎麼拿第二個?其實只要知道第一個元素的位置再搭配簡單的數學加法跟乘法就能算出來了:

起始位置 + (1 x 8) = 1458

同理可證,第三個、第四個直到第 N 個元素就能推導出計算公式:

起始位置 + (N x 8)

到這裡,大家有看出來上面公式裡的 N,剛好就是等於我們平常在講的索引值嗎?所以索引值其實就是記憶體位置的「偏移量」,因此才會從 0 開始算。

所以陣列索引值從 0 開始的概念從滿早期的程式語言開始就有了,大家用著用著也習慣了,Python 以及其它程式語言也都受到影響,所以 Python 的串列索引值也跟是從 0 開始算。

事實上,也不是所有程式語言的索引值都是從 0 開始算的,不同的程式語言對這件事有不同的觀點,像程式語言 LuaFortranCOBOLJuliaR 語言等都是從 1 開始算的,也許在他們的觀點來看,chars[1] 就是第一個或第一欄,看起來更簡單、直覺。

Python 好用的 F 字串!

Python 好用的 F 字串!

Python 裡的 F 字串(F-String)不只是可以直接把變數塞到字串裡、看起來更好看、更好寫而已,它還有一些有趣的用法,像是我們常會遇到需要幫錢錢加上千位數字的逗點,在其它程式語言可能需要透過其它函數或是另外自己寫函數來處理,用 F 字串可以輕鬆做到這件事,例如: