簡單來講,Python程序可以分解成模塊(文件)、語句、表達式以及對象(數據):
1、程序由模塊組成
2、模塊包含語句
3、語句包含表達式
4、表達式建立并處理對象。
所以,Python 代碼主要由兩部分構成:語句和表達式(函數、算術表達式等)。
語句使用關鍵字來組成命令,類似告訴解釋器一個命令。你告訴 Python 做什么,它就為你做什么,語句可以有輸出,也可以沒有輸出。
例如: if a > b : print("Hello World!")
而表達式沒有關鍵字。它們可以是使用數學運算符構成的算術表達式,也可以是使用括號調用的函數。它們可以接受用戶輸入,也可以不接受用戶輸入,有些會有輸出,有些則沒有(在 Python 中未指定返回值的函數會自動返回 None,等價于 NULL)。
例如:a*b (1, 23, 34, 45) abs(-4)
一、編碼聲明
Python3中是按照編碼聲明給出的編碼來讀取源文件的,默認值為UTF-8。在此編碼下,全世界大多數語言的字符可以同時用在字符串、標識符和注釋中。盡管 Python 標準庫僅使用英文字母字符做為標識符,這只是任何可移植代碼應該遵守的約定。如果要正確的顯示所有的字符,你的編輯器必須能識別出文件是 UTF-8 編碼,并且它使用的字體能支持文件中所有的字符。
你可以為源文件指定不同的字符編碼。在 #! 行(首行)后插入一行特殊的注釋行來顯示的定義源文件的編碼:
# -- coding: <encoding-name> --
在Python的文件中,空白行會被解釋器忽略(但在交互模式提示符下不會)。語句和表達式中的空格幾乎都忽略(除了在字符串常量內,以及用在縮進時不會)。#
號注釋總是忽略。文檔字符串會忽略,但是會在運行時自動將其附加到對象上,而且能由文檔工具顯示。
二、邏輯行和物理行
Python程序由多個邏輯行構成,邏輯行的結束由 NEWLINE
詞符表示。通過遵循顯式或隱式行連接規則,一個邏輯行(Python語法定義的一行語句)可以由一個或多個物理行(我們寫的代碼實際所占的一行位置)構成。
物理行是由行尾序列(Linux中的換行符 \n
)終止的字符序列。Python會忽略只包含空格,制表符,換行符和注釋的邏輯行(即不生成NEWLINE詞符號)。
顯示行連接(\)
Python 語句,一般使用換行分隔,也就是說一個物理行為一個邏輯行。兩個或更多 物理行可以使用反斜杠字符 (\
)加入一個邏輯行,也就是讓一條語句橫跨多行。
注:這種方法已經過時了,目前從某種程度上來說,不再提倡使用這種方法,因為關注并維護反斜線比較困難,而且這種做法相當脆弱(反斜線之后可能有空格)。
隱式行連接
在使用閉合操作符時,單一語句可以跨多行書寫(一個邏輯行上的語句存在于多個物理行)。例如:包含在小括號( )、中括號[ ]、花括號{ } 中時可以多行書寫,將要換行的語句可在任何縮進層次開始,但是最好讓他們和上一行垂直對其以便于閱讀,Python會在到達你輸入的閉合括號 ) 、] 和 } 時結束當前語句。另外就是三引號包含下的字符串也可以跨行書寫。如果要在使用反斜線換行和使用括號元素換行作一個選擇,我們推薦使用括號,這樣可讀性會更好。
三、縮進
Python的代碼的層次關系是通過同樣深度的空格或制表符縮進(也就是程序代碼左側的空白空間)來體現的,縮進程度相同的一組語句構成一個代碼塊(組)。同一代碼塊的代碼行必須嚴格左對齊(左邊有同樣多的空格或同樣多的制表符),如果不嚴格遵守這個規則,同一組的代碼就可能被當成另一個組,甚至會導致語法錯誤。
代碼塊會在文件末尾或者觸碰到縮進量較少的行時結束,而更深的嵌套塊就是比所在塊的語句進一步向右縮進。通常來說,頂層(無嵌套)代碼必須于第一層縮進(一般為沒有縮進)開始。
隨著縮進深度的增加,代碼塊的層次也在加深,沒有縮進的代碼塊是最高層次的,別稱為腳本的“main”部分。
使用縮進對齊這種方式組織代碼,不但代碼風格優雅,而且也大大提高了代碼的可讀性。由于 Python 只使用縮進方式表達代碼塊邏輯,因此“神圣的大括號戰爭”永遠不會發生在 Python 身上。
注意:由于不同的平臺的制表符換算成的空格數并不完全相同,如果你的代碼要跨平臺應用,或者會被不同的編輯器讀寫,建議你不要使用制表符。由于使用1個空格過短,使用8個空格又過長,所以我們常用 4個空格 來表示一級縮進。
四、注釋(#)和 文檔字符串
我們使用字符井號 #
,來注釋一個物理行,注釋可以在一行的任何地方開始,解釋器會忽略掉該行 # 之后的所有內容(只要#不是位于字符串常量中)。
#
注釋只能在源代碼中看到,要編寫能夠更廣泛使用的注釋,請使用文檔字符串。通常來講,文檔字符串最適于大型功能的文檔(例如,“我的文件、類、函數做這些事”),而 # 注釋最適合用于較小功能的文檔(例如:“這個表達式做這些事”)
五、同一行書寫多個語句(;)
分號;
允許你將多個語句寫在同一行上,語句之間用分號隔開。而這些語句不能是復合語句也就是說不能在這行開始一個新的代碼塊。
注意: 同一行上書寫多個語句會大大降低代碼的可讀性, Python 雖然允許但不提倡你這么做。
六、模塊
每一個 Python 文件都可以被當成是一個模塊,模塊以磁盤文件的形式存在。當一個模塊變得過大,并且驅動了太多功能的話,就應該考慮拆一些代碼出來另外建一個模塊。模塊里的代碼可以是一段直接執行的腳本,也可以是一堆類似庫函數的代碼,從而可以被別的模塊導入(import)調用。
七、文檔
Python 還提供了一個機制,可以通過 doc 特別變量,動態獲得文檔字串。在模塊、類聲明或函數聲明中,Python會自動的封裝第一個沒有賦值的字符串(通常使用三對引號表示)并賦值給對應對象的 obj.doc 屬性,使得我們可以在程序運行時可以通過訪問對象的doc屬性查看對象的文檔說明。其中 obj是一個模塊,類,或函數的名字。
Python還在標準庫中附帶了PyDoc工具,它知道如何提取文檔字符串并且自動提取其結構化的信息,并將其格式化成各種類型的排列友好的報表。我們可以是引用內置的help() 函數來調用PyDoc提供的接口,從而生成簡單的文字報表。
八、模塊(文件)結構和布局
用模塊(文件)來合理組織你的 Python 代碼是簡單又自然的方法。 你應該建立一種統一且容易閱讀的結構,并將它應用到每一個文件中去。下面就是一種非常合理的布局。
(1) 起始行
通常只有在類 Unix 環境下才使用起始行,有起始行就能夠僅輸入腳本名字來執行腳本,無需直接調用解釋器。
(2)模塊文檔
簡要介紹模塊的功能及重要全局變量的含義,模塊外可通過 module.__doc__
訪問這些內容。
(3)模塊導入
導入當前模塊的代碼需要的所有模塊。每個模塊僅導入一次(當前模塊被加載時),函數內部的模塊導入代碼不會被執行, 除非該函數正在執行。
(4)變量定義
這里定義的變量為全局變量, 本模塊中的所有函數都可直接使用。從好的編程風格角度說,除非必須,否則就要盡量使用局部變量代替全局變量,如果堅持這樣做,你的代碼就不但容易維護,而且還可以提高性能并節省內存。
(5)類定義語句
所有的類都需要在這里定義。當模塊被導入時 class 語句會被執行, 類也就會被定義。類的文檔變量是 class.__doc__
。
(6)函數定義語句
此處定義的函數可以通過 module.function() 在外部被訪問到,當模塊被導入時 def 語句會被執行, 函數也就都會定義好,函數的文檔變量是 function.__doc__
。
(7) 主程序
無論這個模塊是被別的模塊導入還是作為腳本直接執行,都會執行這部分代碼。通常這里不會有太多功能性代碼,而是根據執行的模式調用不同的函數。
注意: 主程序調用 main()函數
主程序代碼通常都和你前面看到的代碼相似,檢查 name 變量的值然后再執行相應的調用。主程序中的代碼通常包括變量賦值, 類定義和函數定義,隨后檢查 name 來決定是否調用另一個函數(通常調用 main()函數)來完成該模塊的功能。主程序通常都是做這些事。 不管用什么名字, 我們想強調一點那就是:這兒是放置測試代碼的好地方。大部分的 Python 模塊都是用于導入調用的,直接運行模塊應該調用該模塊的回歸測試代碼。
很多項目都是只有一個主程序,由它導入所有需要的模塊。所以請記住,絕大部分的模塊創建的目的是為了被別人調用而不是作為獨立執行的腳本。 我們也很可能創建一個 Python 庫風格的模塊,這種模塊的創建目的就是為了被其他模塊調用。總之,只有一個模塊,也就是包含主程序的模塊會被直接執行,或由用戶通過命令行執行,或作為批處理執行, 或由 Unix cron 任務定時執行,或通過 Web 服務器調用,或通過 GUI 執行。
時刻記住一個事實,那就是所有的模塊都有能力來執行代碼。最高級別的 Python 語句,也就是說, 那些沒有縮進的代碼行在模塊被導入時就會執行, 不管是不是真的需要執行。由于有這樣一個“特性”,比較安全的寫代碼的方式就是除了那些真正需要執行的代碼以外, 幾乎所有的功能代碼都在函數當中。再說一遍, 通常只有主程序模塊中有大量的頂級可執行代碼,所有其它被導入的模塊只應該有很少的頂級執行代碼,所有的功能代碼都應該封裝在函數或類當中。
注意: __name__
指示模塊應如何被加載
由于主程序代碼無論模塊是被導入還是被直接執行都會運行, 我們必須知道模塊如何決定運行方向。一個應用程序可能需要導入另一個應用程序的一個模塊,以便重用一些有用的代碼(否則就只能用拷貝粘貼那種非面向對象的愚蠢手段)。 這種情況下,你只想訪問那些位于其它應用程序中的代碼,而不是想運行那個應用程序。因此一個問題出現了,“Python 是否有一種方法能在運行時檢測該模塊是被導入還是被直接執行呢?” 判斷 name 系統變量就是正確答案。
如果模塊是被導入, name 的值為模塊名字
如果模塊是被直接執行, name 的值為 ' main '
九、在主程序中書寫測試代碼
優秀的程序員和軟件工程師,總是會為我們的應用程序提供一組測試代碼或者簡單教程。對那些僅僅為了讓別的程序導入而創建的模塊來說, Python 有效的簡化了這個任務。這些模塊理論上永遠不會被直接執行, 那么,可以讓這個模塊在被直接執行時進行系統測試,而且這樣設置起來一點兒也不難。
測試代碼僅當該文件被直接執行時運行, 也就是說不是被別的模塊導入時。上文及核心筆記中提到如何判斷一個模塊是被直接運行還是被導入。我們應該利用 name 變量這個有利條件。將測試代碼放在一個或者叫 main(), 或者叫 test()(或者你隨便取個啥名字)的函數中,如果該模塊是被當成腳本運行, 就調用這個函數。
這些測試代碼應該隨著測試條件及測試結果的變更及時修改, 每次代碼更新都應該運行這些測試代碼,以確認修改沒有引發新問題。只要堅持這樣做,你的代碼就會足夠健壯,更不用提驗證和測試新特性和更新了。
在主程序中放置測試代碼是測試模塊的簡單快捷的手段。Python 標準庫中還提供了unittest 模塊, 有時候它被稱為 PyUnit, 是一個測試框架。當需要對一個大系統的組件進行正規系統的回規測試時,它就會派上場。
《Python基礎手冊》系列:
Python基礎手冊 1 —— Python語言介紹
Python基礎手冊 2 —— Python 環境搭建(Linux)
Python基礎手冊 3 —— Python解釋器
Python基礎手冊 4 —— 文本結構
Python基礎手冊 5 —— 標識符和關鍵字
Python基礎手冊 6 —— 操作符
Python基礎手冊 7 —— 內建函數
Python基礎手冊 8 —— Python對象
Python基礎手冊 9 —— 數字類型
Python基礎手冊10 —— 序列(字符串)
Python基礎手冊11 —— 序列(元組&列表)
Python基礎手冊12 —— 序列(類型操作)
Python基礎手冊13 —— 映射(字典)
Python基礎手冊14 —— 集合
Python基礎手冊15 —— 解析
Python基礎手冊16 —— 文件
Python基礎手冊17 —— 簡單語句
Python基礎手冊18 —— 復合語句(流程控制語句)
Python基礎手冊19 —— 迭代器
Python基礎手冊20 —— 生成器
Python基礎手冊21 —— 函數的定義
Python基礎手冊22 —— 函數的參數
Python基礎手冊23 —— 函數的調用
Python基礎手冊24 —— 函數中變量的作用域
Python基礎手冊25 —— 裝飾器
Python基礎手冊26 —— 錯誤 & 異常
Python基礎手冊27 —— 模塊
Python基礎手冊28 —— 模塊的高級概念
Python基礎手冊29 —— 包