[![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)