[![hackmd-github-sync-badge](https://hackmd.io/3_lM7pLiSvmRLj7S3SwvoQ/badge)](https://hackmd.io/3_lM7pLiSvmRLj7S3SwvoQ)
<style>
.emp {color:red}
.info {color:green}
details.part {color:#2471A3}
</style>
# 02.Python語言特性
![](https://hackmd.io/_uploads/BJQvXzZzp.png)
## Python 簡介
Python 是由荷蘭電腦科學家 [吉多·范羅蘇姆(Guido van Rossum)](https://zh.wikipedia.org/zh-tw/%E5%90%89%E5%A4%9A%C2%B7%E8%8C%83%E7%BD%97%E8%8B%8F%E5%A7%86) 《[發音](https://forvo.com/word/guido_van_rossum/)》 於 1989 年為了打發聖誕節的空餘時間,設計了以 ABC 語言作為基礎的腳本語言,並因狂熱愛好電視劇《蒙提·派森的飛行馬戲團》(Monty Python’s Flying Circus),故以 Python 為該語言命名,並於 1991 年公開發佈。
![](https://hackmd.io/_uploads/HyDMtVHkp.jpg)
雖然 Python 本質上屬於一種 Scripting 程式語言,但支援完整的物件導向特性,適用於各種作業系統(Windows、Linux、Mac OS),還能夠撰寫網頁(搭配Flask、Django套件),進行科學計算(搭配 NumPy、Pandas、Matplotlib 與 Scikit-Learn 等資料分析模組)。
[Guido](https://gvanrossum.github.io//) 曾經扮演著 Python 軟體基金會的核心管理角色,被暱稱為 Python「仁慈的終身獨裁者」(Benevolent Dictator For Life,BDFL) 表明了他對 Python 的最終話語權。
2018 年為了解決 [PEP 572 – Assignment Expressions](https://peps.python.org/pep-0572/) (Python Enhancement Proposals) 【指派表示式】提案的爭議,在社群討論還未到一個段落時,Guido 獨裁地做出接受 PEP 572 的決定,而這項決定引來了社群內大批反對者的攻擊,Guido 在身心俱疲的情況,對社群發出公開信,表示將[從 BDFL 的位子卸任](https://www.ithome.com.tw/news/124556)。
Guido 同時也在 Zope、Google、Dropbox 等大公司工作,最後於 2019/10/29 宣佈退休,不過 2020/11/12 時,因為覺得退休生活太無聊,所以加入了微軟開發部門,時年 68 歲。
:::success
[Python 的誕生故事](https://buzzorange.com/techorange/2019/08/20/the-history-of-python/):覺得其他程式語言不好用,超狂荷蘭工程師花三個月打造自己的程式語言
:::
Python 是一種易學、功能強大的程式語言。它有高效能的高階資料結構,也有簡單但有效的方法去實現物件導向程式設計。Python 優雅的語法和動態型別,結合其直譯特性,使它成為眾多領域和大多數平臺上,撰寫腳本和快速開發應用程式的理想語言,與 C 或 Java 相較,用 Python 撰寫類似的程式往往只需要 1/5 的時間與程式碼,以下是其特點:
- 簡單易學(大量標準模組與第三方套件)
- 直譯語言
- 動態型別
- 物件導向
- 跨平台
- 開放源碼且社群龐大
- 區分大小寫
![](https://hackmd.io/_uploads/BkdkuJ_dh.png)
表現不佳之處有
- 不是最快的語言
- 函式庫不是最多的
- 在行動裝置方面沒有太多支援
- 不能充分的利用多核處理器
## Python 的型別特性
根據變數的型別檢查時機點,可將程式語言分為二類
- 靜態型別語言:在靜態型別語言中,變數的型別在編譯時期就已經確定,並且通常需要在宣告變數時指定型別。編譯器可在編譯時檢查型別錯誤,並在執行前進行型別檢查,可以減少執行期發生的錯誤。如 C 語言。
- 動態型別語言:在動態型別語言中,變數的型別在執行時期根據值的內容動態確定。這表示不需要在變數聲明時指定型別,並可在執行時期動態變化型別,但型別的錯誤問題就只會在執行時期才會被檢測到。如 Python 語言。
![](https://hackmd.io/_uploads/rJt7hmTgp.png)
Python 是一種既是【動態型別】又是【強型別】的語言
1. 動態型別 (Dynamic Type):
在 Python 中,變數的型別無需事先宣告,且可在執行期間改變變數的型別。例如:
```python=
x = 5 # 此時 x 是整數型別
x = "Hello" # 此時 x 變成字串型別
```
2. 強型別 (Strong Type):
Python 是一種強型別語言,這意味著它要求進行嚴格的型別匹配,不允許進行隱含的、不安全的型別轉換。例如,在 Python 中,不允許將不同型別的變數直接相加,除非明確的【強制】轉換型別:
```python=
a = 5 # 整數型別
b = "10" # 字串型別
# 會引發 TypeError 錯誤,因為 Python 不允許整數和字串相加
result = a + b
# 必須將字串進行強制轉型為整數才能相加
result = a + int(b)
```
:::info
靜態型別(Static Type)語言在程式的編譯(compiling)時期就會做變數的型別檢查,因此需要事先做出型別宣告讓編譯器確定現在這個變數的型別為何,而動態型別語言是執行時期做型別檢查,藉著存在變數裡的內容的型態來確定這個變數的型別。
:::
## Python的排行
根據 [IEEE Spectrum 2023 年頂尖程式語言排名](https://spectrum.ieee.org/the-top-programming-languages-2023)與 [TIOBE 指數](https://www.tiobe.com/tiobe-index/) 看來,Python 位居程式語言流行排行榜的第一名。雖然像 C++ 這樣的編譯語言並沒有消失,但很明顯,Python 正成為計算的通用語言。
![](https://hackmd.io/_uploads/rkKlJyq16.png)
:::info
TIOBE編程社區指數(TIOBE programming community index)是一種衡量程式語言流行度的標準,該指數涵蓋了全球熟練的工程師、課程、第三方供應商和流行的搜索引擎如 Google、Bing、Yahoo、維基百科、Amazon、YouTube和百度的搜索結果。該指數於 2001 年推出,每月更新一次。TIOBE 的字義為「認真的重要性」,[發音為 TIO-BE](https://zh.howtopronounce.com/tiobe)。
:::
:::success
其它程式語言排行參考
- [GitHub Octoverse](https://octoverse.github.com/)
- [GitHub Language Stats](https://madnight.github.io/githut/)
- [PYPL PopularitY of Programming Language](https://pypl.github.io/PYPL.html)
:::
## Python 格言
Python 格言 (The Zen of Python) 最早由 Tim Peters 在 Python 郵件列表中發表。
Python 的設計哲學是「優雅」、「明確」、「易讀」。主張「用一種方法,最好是只有一種方法來做一件事」。在設計Python語言時,如果面臨多種選擇,Python開發者一般會拒絕花俏的語法,而選擇明確沒有或者很少有歧義的語法。這些準則被稱為「Python 格言」。
> Tim Peters 是美國軟體開發人員,他對 Python 語言及其原始 CPython 的實現有主要貢獻。
我們可以在 [PEP 20](https://peps.python.org/pep-0020/) 看到其內容,或在 Python 互動模式下執行 `import this` 就能看到,內容請參考下列翻譯。
```
Beautiful is better than ugly. Explicit is better than implicit.
> 優美勝過醜陋,明確勝過隱晦
Simple is better than complex. Complex is better than complicated
> 簡潔勝過複雜,複雜勝過晦澀難解
Flat is better than nested. Sparse is better than dense. Readability counts
> 扁平結構勝過巢狀結構,分散勝過密集,程式碼的可讀性很重要
Special cases aren't special enough to break the rules Although practicality beats purity
> 雖然實用比完美主義重要,但特例亦不可違背原則
Errors should never pass silently Unless explicitly silenced
> 錯誤絕不能悄悄忽略,除非它明確需要如此
In the face of ambiguity, refuse the temptation to guess
> 面對不確定性,拒絕妄加猜測
There should be one and preferably only one obvious way to do it Although that way may not be obvious at first unless you're Dutch
> 解決辦法應該明確,而且最好只有一個,當然要達成這些目標並非一蹴可及,除非你是那個荷蘭人(Python之父),呵呵
Now is better than never Although never is often better than *right* now
> 坐而言不如起而行,但欲速則不達(想好再行動)
If the implementation is hard to explain, it's a bad idea
> 如果你的程式碼實作很難向他人解釋,那解決想法肯定不夠好
If the implementation is easy to explain, it may be a good idea
> 如果你的程式碼實作讓人一看就懂,那解決想法肯定不錯
Namespaces are one honking great idea -- let's do more of those!
> 命名空間是個絕佳機制,要充分運用
```
:::danger
Guido 的重要見解之一是程式碼被閱讀的次數,遠大於被撰寫的次數。
> One of Guido’s key insights is that code is read much more often than it is written
:::
## Python 程式碼風格指引(PEP 8)
撰寫 Python 程式的規範,官方稱之為 [Style Guide for Python Code](https://peps.python.org/pep-0008/),因為是第 8 個提案,所以又稱為 PEP 8,一開始是 Python 之父 Guido 自己的撰碼風格,慢慢後來演變至今,目的在於幫助開發者寫出可讀性高且風格一致的程式。希望大家所寫的程式都非常的 Pythonic (具有Python風格的),<span class="highlight">**請務必整個閱讀一遍喔**</span>。
![](https://hackmd.io/_uploads/BknpDV6bp.png)
### PEP8 指引摘要
- 縮排:使用四個空格作為縮排,而非使用 Tab 鍵。
- 行長:每行盡量不超過 79 個字元長度,若必須分行可使用行接續符號【\】,在圓括號【()】、方括號【[]】、大括號【{}】等敘述可直接斷行,但運算子要放在前方。
- 命名風格:函式名稱、變數名稱與模組名稱以小寫且若有2個單字,應以蛇型命名(Snake case)用底線(_)作為區隔,例如:`my_variable_name`。
- 空格:在運算子、逗號、冒號前後需要留一個空格。例如:`x = y + 2`,但參數的等號兩邊則不要加空格。
- 空行:將最高層級的 function 和 class 定義以兩個空行分隔
- 單行註解:使用一個【#】符號做為注解,可以自成一行也可以放在敘述的最後。
- 多行(區塊)註解:使用三個單引號【'】做為注解,並應該在代碼上方進行,以句號為結尾。
- 模組引用:不同模組應放不同行,相同套件不同模組才放同行
- 支援 UTF-8,區分大小寫
- 非 ASCII 資料應使用 \x、\u 或 \U 等轉義字符表示
:::info
相關連結:
- [PEP8 的中文翻譯](https://wiki.jiayun.info/PEP_8_--_Style_Guide_for_Python_Code)
- [常見命名規則介紹](https://unauna1129.medium.com/%E5%B8%B8%E8%A6%8B%E5%91%BD%E5%90%8D%E8%A6%8F%E5%89%87%E4%BB%8B%E7%B4%B9-eebc6790a8ef)
- [Clean Code 無瑕的程式碼 | 閱讀筆記](https://medium.com/%E6%89%8B%E5%AF%AB%E7%AD%86%E8%A8%98/clean-code-index-51e209cc47db)
:::
:::danger
檔案(原始碼或文字檔)的最後一行必須以空行(換行符號)終止,否則許多文字處理的工具會作動不完全。
:::
### 提升程式品質
團隊一致的 code 風格,可以大幅提升 [Code Review (代碼審查)](https://blog.alantsai.net/posts/2019/05/code-review-what-is-code-review-and-why-we-want-to-do-it) 的速度,也可以讓每個人的程式碼更好閱讀,而要 review 的每一段 code,應該只要有一個相關的修改,避免包含多個修改,導致 review 要花許多時間。
所有程式語言都應該搭配 3 種重要的工具:
1. Formatter(格式化器):著重在美觀、排版、風格,例如行距、縮排、運算元周圍的間距...等,作用時會直接調整程式碼。
2. Linter(規範器):著重在語法、效能、正確性,例如檢測到使用未初始化或未定義的變數,呼叫未定義的函數,缺少括號...等,作用時會給建議與警告但不會調整程式碼。
3. [Pull Request(拉取請求)](https://blog.alantsai.net/posts/2019/05/code-review-02-what-is-pull-request-and-how-to-create-it-in-azure-devops):主動地要求開發者納入自己開發的程式,將本地端儲存庫上的程式碼,整併到對方的儲存庫上。
![](https://hackmd.io/_uploads/S1qxDE6bT.png)
VScode 在 Python 語言對前 2 種工具,提供了對應的延伸套件如下:
1. Formatter:[Black Formatter](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter)、yapf、autopep8
2. Linter:[Flake8](https://marketplace.visualstudio.com/items?itemName=ms-python.flake8)、Pylint
**使用 black formatter 前**
```python=
def divide(a,b):
if b==0:
return None
else:
return a/b
result = divide(10,2)
print(result)
```
**使用 black formatter 後**
```python=
def divide(a, b):
if b == 0:
return None
else:
return a / b
result = divide(10, 2)
print(result)
```
**Flake8 Linter 給出的建議**
```
E231: missing whitespace after ','
E225: missing whitespace around operator
E226: missing whitespace around arithmetic operator
E305: expect 2 blank lines after class or function defination
W292: no newline at end of file
```
:::success
參考:[Python Flake8 與 Black Formatter 擴充套件快速上手](https://blog.kyomind.tw/flake8-and-black/)
:::
#### VScode 使用者設定檔參考:
以下設定適用於已安裝 [isort](https://marketplace.visualstudio.com/items?itemName=ms-python.isort) / [Black formatter](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter) / [Flake8](https://marketplace.visualstudio.com/items?itemName=ms-python.flake8)、[One Dark Pro](https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme) 等套件,並使用 Cmder 作為預設終端機的情形。
```json=
{
"editor.formatOnType": true,
"editor.mouseWheelZoom": true, // 視窗縮放
"editor.fontSize": 14,
"editor.unicodeHighlight.nonBasicASCII": false,
"editor.minimap.enabled": false,
"editor.formatOnSave": true,
"editor.accessibilitySupport": "off",
"editor.guides.indentation": true,
"files.encoding": "utf8",
"files.autoSave": "onFocusChange", // 失焦自動儲存
"files.trimTrailingWhitespace": true, // 儲存的時候,會幫你自動過濾多餘的空格
"files.autoGuessEncoding": true,
"workbench.colorTheme": "One Dark Pro Darker",
"workbench.editor.highlightModifiedTabs": true,
"workbench.colorCustomizations": {
// 層級括號顏色,從 1 至 6 層,此處只設定了 5 層
"editorBracketHighlight.foreground1": "#7777ff",
"editorBracketHighlight.foreground2": "#8a2be2",
"editorBracketHighlight.foreground3": "#DC143C",
"editorBracketHighlight.foreground4": "#5eaaa8",
"editorBracketHighlight.foreground5": "#800080",
// 異常括號的顏色,比如多出來的結尾括號
"editorBracketHighlight.unexpectedBracket.foreground": "#ffffff",
},
"workbench.editor.enablePreview": false,
"window.zoomLevel": 2, // 視窗縮放程度
"[bat]": {
"files.encoding": "cp950",
},
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
},
"black-formatter.args": [
"--line-length=100",
"--skip-string-normalization"
],
"flake8.args": [
"--max-line-length=100",
"--ignore=E131,E302",
],
"isort.args": [
"--src=${workspaceFolder}",
"--line-length=100",
],
"isort.check": true,
// "terminal.integrated.defaultProfile.windows": "Command Prompt",
"terminal.integrated.defaultProfile.windows": "Cmder",
"terminal.integrated.profiles.windows": {
"Cmder": {
"name": "Cmder",
"path": [
"${env:windir}\\Sysnative\\cmd.exe",
"${env:windir}\\System32\\cmd.exe"
],
"args": ["/k", "${env:cmder_root}\\vendor\\bin\\vscode_init.cmd"],
"icon": "terminal-cmd",
"color": "terminal.ansiGreen"
},
},
}
```
## Python 的底層運作
直譯語言依原始碼產生機械碼的方式可分為二類
1. 直接將原始碼經直譯器(Interpreter)直譯為機械碼(Machine Code)。
2. 先將原始碼經直譯器直釋為位元組碼(Byte Code),然後由虛擬機在執行時立即轉換成特定平台的機械碼(這種技術稱為JIT 即時編譯)。
Python 為了加快程式碼執行的效率,採取的是第2類方式。
``` mermaid
graph LR
原始碼-->|直譯器直譯| 機械碼
```
``` mermaid
graph LR
原始碼-->|直譯器直譯| 位元組碼-->|虛擬機編譯| 機械碼
```
:::info
位元組碼(Byte Code)是一種中間碼,不是本機的機械碼,但虛擬機可以將它編譯成特定平台上的機械碼,從而加速程式碼的執行。
可將 Byte Code 視為虛擬機的機械碼,虛擬機會根據作業系統的不同產生對應的機械碼。
:::
![](https://hackmd.io/_uploads/Byp1utX5n.png)
CPython 使用 C 語言來實現【直譯器】和【虛擬機】,並提供了一個 Python 運行環境。
- 直譯器(interpreter)負責解析 Python 原始碼(副檔名 .py)並將其轉換為位元組碼(副檔名 .pyc)。它處理了代碼的語法分析、語義分析,並生成對應的位元組碼。直譯器還執行一些基本的代碼優化。
- 虛擬機(PVM; Python Virtual Machine) 負責讀取、解釋和執行位元組,並管理 Python 程序的運行時環境。PVM 負責記憶管理、變數作用域、運行時異常處理等。
:::success
更詳細的說明,請參考:[Python 到底怎麼被執行?](https://medium.com/citycoddee/python%E9%80%B2%E9%9A%8E%E6%8A%80%E5%B7%A7-5-python-%E5%88%B0%E5%BA%95%E6%80%8E%E9%BA%BC%E8%A2%AB%E5%9F%B7%E8%A1%8C-%E7%9B%B4%E8%AD%AF-%E7%B7%A8%E8%AD%AF-%E5%AD%97%E7%AF%80%E7%A2%BC-%E8%99%9B%E6%93%AC%E6%A9%9F%E7%9C%8B%E4%B8%8D%E6%87%82-553182101653)、[Python 的底層架構](https://goinglearn.com.tw/programming-languages/151-python-%E7%9A%84%E5%BA%95%E5%B1%A4%E6%9E%B6%E6%A7%8B)
:::
## 學習參考
- [【編譯 vs. 直譯】 / 【靜態 vs. 動態】 / 【強型別 vs. 弱型別】](https://growingdna.com/language-type-compiler/)
- [值得參考的 Coding Style 整理筆記](https://clay-atlas.com/blog/2020/07/23/python-%E5%80%BC%E5%BE%97%E5%8F%83%E8%80%83%E7%9A%84-coding-style-%E6%95%B4%E7%90%86%E7%AD%86%E8%A8%98/)
- [空行讓Python更簡潔](https://iapyeh.readthedocs.io/en/latest/blogs/technical/docs_style_review_twisted.html)
- [30天python雜談系列](https://ithelp.ithome.com.tw/users/20107274/ironman/1578)
- [IEEE Spectrum年度頂尖程式語言排名Python穩坐第一](https://www.ithome.com.tw/news/158524)