# Chapter 1 你的第一個 Python 程序
> " Don’t bury your burden in saintly silence. You have a problem? Great. Rejoice, dive in, and investigate. "
> — [Ven. Henepola Gunaratana](http://en.wikiquote.org/wiki/Buddhism)
## Diving In
通常程序設計的書籍都會以一堆關于基礎知識的章節開始,最終逐步的構建一些有用的東西。讓我們跳過所有的那些東西,來看一個完整的、可以直接運行的 Python 程序。可能剛開始你根本看不懂,但不要擔心,因為你會去一行一行的仔細研究。但是首先還是要通讀一遍,看看里面什么東西(如果有的話)是你可以看懂的。
```
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
'''Convert a file size to human-readable form.
Keyword arguments:
size -- file size in bytes
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
if False, use multiples of 1000
Returns: string
'''
if size < 0:
raise ValueError('number must be non-negative')
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
for suffix in SUFFIXES[multiple]:
size /= multiple
if size < multiple:
return '{0:.1f} {1}'.format(size, suffix)
raise ValueError('number too large')
if __name__ == '__main__':
print(approximate_size(1000000000000, False))
print(approximate_size(1000000000000))
```
現在讓我們從命令行來運行這個程序。在 Windows 上,類似這樣:
```
c:\home\diveintopython3\examples> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB
```
在 Mac OS X 或者 Linux 上,類似這樣:
```
you@localhost:~/diveintopython3/examples$ python3 humansize.py
1.0 TB
931.3 GiB
```
剛剛發生了什么?你執行了你的第一個 Python 程序。你從命令行調用了 Python 解釋器,并且傳遞了一個你想 Python 去執行的腳本的名稱。這個腳本定義了一個單一的函數,這個 `approximate_size()` 函數把一個精確到字節的文件大小計算成一個有漂亮格式(大約計算的)的大小。(你可能已經在 Windows Explorer,或者 Mac OS X Finder,或者 Linux 上的 Nautilus 或 Dolphin 或 Thunar 看到過這個。如果你按照多列的列表來顯示一個文件夾的文檔,它就會顯示一個包含文檔圖標、文檔名稱、大小、類型、最后修改日期等等信息的表格。如果這個文件夾包含一個 1093 字節大小名叫 `TODO` 的文件,你的文件管理器將不會顯示成 `TODO 1093 bytes`,而用 `TODO 1 KB` 的顯示格式代替。那就是 `approximate_size()` 函數所做的事情。)
看看這個腳本的底部,你會看到對 `print(approximate_size(`arguments`))` 的兩次調用。這些叫做函數調用 —— 第一個調用了 `approximate_size()` 函數并傳遞了一些參數,接著直接把返回值傳遞給了 `print()` 函數。這個 `print()` 函數是內置的,你將從不會看到它的一個顯式的聲明。你只管在需要的任何時候任何地方使用它就行。(有很多內置函數,更多的函數獨立于各個 _modules_ (模塊)里面。保持耐心,你會逐步熟悉它們的。)
那么為什么每次在命令行運行腳本都會給你同樣的輸出結果呢?我們將講解這個。首先,讓我們來看一下 `approximate_size()` 函數。
## 聲明函數
像多數其他語言一樣, Python 也有函數, 但是它沒有像 C++ 一樣的單獨頭文件,也沒有像 Pascal 一樣 `interface`/`implementation` (接口/實現)部分。當你需要一個函數的時候,就像這樣聲明它就行:
```
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
```
當你需要一個函數的時候,只要聲明它就行。
函數聲明以關鍵字 `def` 開頭,緊跟著函數的名稱,然后是用括號括起來的參數。多個參數以逗號分割。
同時注意,函數不定義一個返回數據類型。 Python 函數不指定它們的返回值的類型,甚至不指定它們是否返回一個值。(事實上,每個 Python 函數都返回一個值,如果這個函數曾經執行了 `return` 語句,它將返回那個值,否則它將返回 Python 里面的空值 `None`。)
> ?在某些語言里面,函數(返回一個值)以 `function` 開頭,同時子程序(不返回值的)以 `sub` 開頭。 Python 里面沒有子程序。所有的東西都是一個函數,所有的函數都返回一個值(即使它是 `None` 值),并且所有的函數都以 `def` 開頭。
`approximate_size()` 函數有兩個參數?—?`size` 和 `a_kilobyte_is_1024_bytes`?—?但都沒有指定數據類型。在 Python 里面,變量從來不會顯式的指定類型。Python 會在內部算出一個變量的類型并進行跟蹤。
> ?在 Java 和其他靜態類型的語言里面,你必須給函數返回值和每個函數參數指定數據類性。而在 Python 里面,你從來不需要給任何東西指定顯式的數據類型。根據你賦的值,Python 會在內部對數據類型進行跟蹤。
### 可選的和命名的參數
Python 允許函數函數有默認值。如果函數被調用的時候沒有指定參數,那么參數將使用默認值。不僅如此,通過使用命名參數還可以按照任何順序指定參數。
讓我們再看一下 `approximate_size()` 函數的聲明:
```
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
```
第二個參數 `a_kilobyte_is_1024_bytes` 指定了一個默認值 `True`。 意思是這個參數是 _optional (可選的)_,你可以在調用的時候不指定它,Python 將看成你調用的時候使用了 `True` 作為第二個參數。
現在看一下這個腳本的底部:
```
if __name__ == '__main__':
```
1. 這個對 `approximate_size()` 函數的調用指定了兩個參數。在 `approximate_size()` 函數里面,`a_kilobyte_is_1024_bytes` 的值將為 `False`,因為你顯式的傳入了 `False` 作為第二個參數。
2. 這個對 `approximate_size()` 函數的調用只指定了一個參數。但這是可以的,因為第二個參數是可選的!由于調用者沒有指定,第二個參數就會使用在函數聲明的時候定義的默認值 `True`。
你也可以通過名稱將值傳入一個函數。
```
>>> from humansize import approximate_size
'4.0 KB'
'4.0 KB'
'4.0 KB'
File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
```
1. 這個對 `approximate_size()` 函數的調用給第一個參數((`size`)指定了值 `4000`,并且給名為 `a_kilobyte_is_1024_bytes` 的參數指定了值 `False`。(那碰巧是第二個參數,但這沒有關系,馬上你就會了解到。)
2. 這個對 `approximate_size()` 函數的調用給名為 `size` 參數指定了值 `4000`,并為名為 `a_kilobyte_is_1024_bytes` 的參數指定了值 `False`。(這些命名參數碰巧和函數聲明時列出的參數順序一樣,但同樣不要緊。)
3. 這個對 `approximate_size()` 函數的調用給名為 `a_kilobyte_is_1024_bytes` 的參數指定了值 `False`,然后給名為 `size` 的參數指定了值 `4000`。(看到了沒?我告訴過你順序沒有關系。)
4. 這個調用會失敗,因為你在命名參數后面緊跟了一個非命名(位置的)的參數,這個一定不會工作。從左到右的讀取參數列表,一旦你有一個命名的參數,剩下的參數也必須是命名的。
5. 這個調用也會失敗,和前面一個調用同樣的原因。 是不是很驚訝?別忘了,你給名為 `size` 的參數傳入了值 `4000`,那么“顯然的” `False` 這個值意味著對應了 `a_kilobyte_is_1024_bytes` 參數。但是 Python 不按照這種方式工作。只要你有一個命名參數,它右邊的所有參數也都需要是命名參數。
## 編寫易讀的代碼
我不會長期指手劃腳的來煩你,解釋給你的代碼添加文檔注釋的重要性。只要知道代碼被編寫一次但是會被閱讀很多次,而且你的代碼最要的讀者就是你自己,在編寫它的六個月以后(_例如_,當你忘記了所有的東西但是又需要去修正一些東西的時候)。 Python 使得編寫易讀的代碼非常容易,因此要利用好這個優勢。六個月以后你將會感謝我。
### 文檔字符串
你可以通過使用一個文檔字符串(簡稱 `docstring` )的方式給 Python 添加文檔注釋。在這個程序中,這個 `approximate_size()` 函數有一個 `docstring`:
```
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
'''Convert a file size to human-readable form.
Keyword arguments:
size -- file size in bytes
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
if False, use multiples of 1000
Returns: string
'''
```
每個函數都值得有一個合適的 docstring (文檔字符串)。
三重引號表示一個多行的字符串。在開始引號和結束引號之間的所有東西都屬于一個單獨的字符串的一部分,包括回車、前導空格、和其他引號字符。你可以在任何地方使用它們,但是你會發現大部分時候它們在定義 `docstring` (文檔注釋)的時候使用。
> ?三重引號也是一種容易的方法,用來定義一個同時包含單引號和雙引號的字符串,就像 Perl 5 里面的 `qq/.../` 一樣。
三重引號之間的所有東西都是這個函數的 `docstring` (文檔字符串),用來用文檔描述這個函數是做什么的。一個 `docstring` (文檔字符串),如果有的話,必須是一個函數里面定義的第一個東西(也就是說,緊跟著函數聲明的下一行)。 你不需要嚴格的給你的每個函數提供一個 `docstring` (文檔字符串),但大部分時候你總是應該提供。我知道你在曾經使用過的每一種程序語言里面聽說過這個,但是 Python 給你提供了額外的誘因:這個 `docstring` (文檔字符串)就像這個函數的一個屬性一樣在運行時有效。
> ?很多 Python 的集成開發環境(IDE)使用 `docstring` (文檔字符串)來提供上下文敏感的文檔,以便于當你輸入一個函數名稱的時候,它的 `docstring` 會以一個提示文本的方式顯式出來。這可能會極其有用,但它只有在你寫出好的 `docstring` (文檔字符串)的時候才有用。
## `import` 的搜索路徑
在進一步講解之前,我想簡要的說一下庫的搜索路徑。當你試圖導入(import)一個模塊的時候,Python 會尋找幾個地方。具體來說,它會搜尋在 `sys.path` 里面定義的所有目錄。這只是一個列表,你可以容易地查看它或者使用標準的列表方法去修改它。(在[內置數據類型](native-datatypes.html#lists)你會了解更多關于列表的信息。)
```
['',
'/usr/lib/python31.zip',
'/usr/lib/python3.1',
'/usr/lib/python3.1/plat-linux2@EXTRAMACHDEPPATH@',
'/usr/lib/python3.1/lib-dynload',
'/usr/lib/python3.1/dist-packages',
'/usr/local/lib/python3.1/dist-packages']
<module 'sys' (built-in)>
['/home/mark/diveintopython3/examples',
'',
'/usr/lib/python31.zip',
'/usr/lib/python3.1',
'/usr/lib/python3.1/plat-linux2@EXTRAMACHDEPPATH@',
'/usr/lib/python3.1/lib-dynload',
'/usr/lib/python3.1/dist-packages',
'/usr/local/lib/python3.1/dist-packages']
```
1. 導入 `sys` 模塊,使它的所有函數和屬性可以被使用。
2. `sys.path` 是一個目錄名稱的列表,它構成了當前的搜索路徑。(你會看到不一樣的結果,這取決于你的操作系統,你正在運行的 Python 的版本,以及它原來被安裝的位置。) Python 會從頭到尾的瀏覽這些目錄(按照這個順序),尋找一個和你正要導入的模塊名稱匹配的 `.py` 文件。
3. 其實,我說謊了。真實情況比那個更加復雜,因為不是所有的模塊都按照 `.py` 文件來存儲。有些,比如 `sys` 模塊,屬于內置模塊(_built-in modules_), 他們事實上被置入到 Python 本身里面了。 內置模塊使用起來和常規模塊一樣,但是無法取得它們的 Python 源代碼,因為它們不是用 Python 寫的!( `sys` 模塊是用 C 語言寫的。)
4. 通過添加一個目錄名稱到 `sys.path` 里,你可以在運行時添加一個新的目錄到 Python 的搜索路徑中,然后無論任何時候你想導入一個模塊,Python 都會同樣的去查找那個目錄。只要 Python 在運行,都會一直有效。
5. 通過使用 `sys.path.insert(0, `new_path`)`,你可以插入一個新的目錄到 `sys.path` 列表的第一項,從而使其出現在 Python 搜索路徑的開頭。這幾乎總是你想要的。萬一出現名字沖突(例如,Python 自帶了版本 2 的一個特定的庫,但是你想使用版本 3),這個方法就能確保你的模塊能夠被發現和使用,替代 Python 自帶的版本。
## 一切都是對象
假如你還不了解,我重復一下,我剛剛說過 Python 函數有屬性,并且那些屬性在運行時是可用的。一個函數,就像 Python 里面所有其他東西一樣,是一個對象。
運行交互式的 Python Shell,按照下面的執行:
```
4.0 KiB
Convert a file size to human-readable form.
Keyword arguments:
size -- file size in bytes
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
if False, use multiples of 1000
Returns: string
```
1. 第一行導入了作為一個模塊的 `humansize` 程序?—?我們可以交互式的使用的一大塊代碼,或者來自于一個更大的 Python 程序。一旦你導入了一個模塊,你就可以引用它的任何公有的函數、類、或者屬性。模塊可以通過這種方式訪問其他模塊的功能,同樣的你也可以在 Python 交互式的 Shell 里面做這樣的事情。這是一個重要的概念,貫穿這本書,你會看到更多的關于它的內容。
2. 當你想使用在導入的模塊中定義的函數的時候,你需要包含模塊的名稱。因此你不能僅僅指明 `approximate_size`,它必須是 `humansize.approximate_size` 才行。如果你曾經使用過 Java 里面的類,你就會依稀的感覺到這種方式比較熟悉。
3. 除了按照你期望的方式調用這個函數,你查看了這個函數的其中一個屬性: `__doc__`。
> ?Python 里面的 `import` 就像 Perl 里面的 `require`。一旦你導入(`import`)了一個 Python 模塊,你就可以通過 ``module`.`function`` 的方式訪問它的函數;一旦你要求(`require`)了一個 Perl 模塊,你就可以通過 ``module`::`function`` 的方式訪問它的函數。
### 什么是一個對象?
Python 里面的所有東西都是對象,所有東西都可以有屬性和方法。所有函數都有一個內置的屬性 `__doc__`,用來返回這個函數的源代碼里面定義的文檔字符串(`docstring`)。 `sys` 模塊是一個對象,它有(除了別的以外)一個名叫 `path` 的屬性,等等。
不過,這還是沒有回答這個更基礎的問題:什么是一個對象?不同的程序語言用不同的方式定義了“對象”。在有些地方,它意味著_所有的_對象_必須_要有屬性和方法;在另一些地方,它意味著所有的對象都是可衍生(可以創建子類)的。在 Python 里面,定義更加寬松。有些對象既沒有屬性也沒有方法,然而它可以有。不是所有的對象都是可衍生的。但是,所有的東西都是對象,從這個意義上說,它能夠被賦值到一個變量或者作為一個參數傳入一個函數。
你可能從其他程序語言環境中聽說過 “first-class object” 的說法。在 Python 中,函數是 _first-class objects_,你可以將一個函數作為一個參數傳遞給另外一個函數;模塊是 _first-class objects_,你可以把整個模塊作為一個參數傳遞給一個函數;類是 first-class objects,而且類的單獨的實例也是 first-class objects。
這個很重要,因此剛開始我會重復幾次以防你忘記了:_在 Python 里面所有東西都是對象_。字符串是對象,列表是對象,函數是對象,類是對象,類的實例是對象,甚至模塊也是對象。
## 代碼縮進
Python 函數沒有明確的開始(`begin`)或者結束(`end`),也沒有用大括號來標記函數從哪里開始從哪里停止。唯一的定界符就是一個冒號(`:`)和代碼自身的縮進。
```
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
size /= multiple
if size < multiple:
return '{0:.1f} {1}'.format(size, suffix)
raise ValueError('number too large')
```
1. 代碼塊是通過它們的縮進來定義的。我說的“代碼塊”,意思是指函數,`if` 語句、 `for` 循環、 `while` 循環,等等。 縮進表示一個代碼塊的開始,非縮進表示一個代碼的結束。沒有明確的大括號、中括號、或者關鍵字。這意味著空白很重要,而且必須要是一致的。在這個例子中,這個函數按照四個空格縮進。它不需要一定是四個空格,只是需要保持一致。第一個沒有縮進的行標記了這個函數的結束。
2. 在 Python 中,一個 `if` 語句后面緊跟了一個代碼塊。如果 `if` 表達式的值為 true 則縮進的代碼會被執行,否則它會跳到 `else` 代碼塊(如果有的話)。注意表達式的周圍沒有括號。
3. 這一行在 `if` 代碼塊里面。這個 `raise` 語句將拋出一個異常(類型是 `ValueError` ),但只有在 `size < 0` 的時候才拋出。
4. 這_不是_函數的結尾。完全空白的行不算。它們使代碼更加易讀,但它們不算作代碼塊的定界符。這個函數在下一行繼續。
5. 這個 `for` 循環也標記了一個代碼塊的開始。代碼塊可以包含多行,只要它們都按照同樣的數額縮進。這個 `for` 循環里面有三行。對于多行的代碼塊,也沒有其他特殊的語法,只要縮進就可以了。
在剛開始的一些反對聲和一些類比到 Fortran 的嘲笑之后,你將會平和的看待這個并開始領會到它的好處。一個主要的好處是所有的 Python 程序看起來都類似,因為縮進是一個語言的要求,不是一個風格的問題。這使得閱讀和理解其他人的 Python 代碼更加容易。
> ?Python 使用回車符來分割語句,使用一個冒號和縮進來分割代碼塊。 C++ 和 Java 使用分號來分割語句,使用大括號來分割代碼塊。
## 異常
異常在 Python 中無處不在。事實上在標準 Python 庫里面的每個模塊都使用它們,而且在很多不同情形下, Python 自身也會拋出異常。貫穿這本書,你會反復的看到它們。
什么是一個異常?通常情況下,它是一個錯誤,提示某個東西出問題了。(不是所有的異常都是錯誤,但目前來說別擔心那個) 某些程序語言鼓勵對錯誤返回代碼的使用,你可以對它進行_檢查_。 Python 鼓勵對異常的使用,你可以對它進行_處理_。
當一個錯誤發生在 Python Shell 里面的時候,它會打印一些關于這個異常以及它如何發生的詳細信息,就此而已。這個被稱之為一個 _未被處理_ 的異常。在這個異常被拋出的時候,沒有代碼注意到并處理它,因此它把它的路徑冒出來,返回到 Python Shell 的最頂層,輸出一些調試信息,然后圓滿結束。在這個 Shell 中,這沒什么大不了的,但是如果在你的實際 Python 程序正在運行的時候發生,并且對這個異常沒有做任何處理的話,整個程序就會嘎的一聲停下來。可能那正是你想要的,也可能不是。
> ?不像 Java, Python 函數不聲明它們可能會拋出哪些異常。它取決于你去判斷哪些可能的異常是你需要去捕獲的。
一個異常不會造成整個程序崩潰。不過,異常是可以被_處理_的。有時候一個異常是真正地由于你代碼里面的一個 bug 所引起的(比如訪問一個不存在的變量),但有時候一個 異常是你可以預料到的東西。如果你在打開一個文件,它有可能不存在。如果你在導入一個模塊,它可能沒有被安裝。如果你在連接到一個數據庫,它有可能是無效的,或者你可能沒有訪問它需要的安全認證信息。如果你知道某行代碼可能拋出一個異常,你應該使用 `try...except` 塊來處理這個異常。
> ?Python 使用 `try...except` 塊來處理異常,使用 `raise` 語句來拋出異常。 Java 和 C++ 使用 `try...catch` 塊來處理異常,使用 `throw` 語句來拋出異常。
這個 `approximate_size()` 函數在兩個不同的情況下拋出異常:如果給定的 `size` 的值大于這個函數打算處理的值,或者如果它小于零。
```
if size < 0:
raise ValueError('number must be non-negative')
```
拋出一個異常的語法足夠簡單。使用 `raise` 語句,緊跟著異常的名稱,和一個人們可以讀取的字符串用來調試。這個語法讓人想起調用的函數。(實際上,異常是用類來實現的,這個 `raise` 語句事實上正在創建一個 `ValueError` 類的實例并傳遞一個字符串 `'number must be non-negative'` 到它的初始化方法里面。但是,[我們已經有些超前了](iterators.html#defining-classes)!)
> ?你不需要在拋出異常的函數里面去處理它。如果一個函數沒有處理它,這個異常會被傳遞到它的調用函數,然后那個函數的調用函數,等等“在這個堆棧上面。” 如果這個異常從來沒有被處理,你的程序將會崩潰, Python 將會打印一個 “traceback” 的標準錯誤信息,并以此結束。這也可能正是你想要的,它取決于你的程序具體做什么。
### 捕獲導入錯誤
其中一個 Python 的內置異常是 `ImportError`,它會在你試圖導入一個模塊并且失敗的時候拋出。這有可能由于多種原因引起,但是最簡單的情況是當在你的 [import 搜索路徑](#importsearchpath)里面找不到這個模塊的時候會發生。你可以用這個來包含可選的特性到你的程序中。例如, [這個 `chardet` 庫](case-study-porting-chardet-to-python-3.html) 提供字符編碼自動檢測。也許你的程序想在這個庫存在的時候使用它,但是如果用戶沒有安裝,也會優雅地繼續執行。你可以使用 `try..except` 塊來做這樣的事情。
```
<mark>try</mark>:
import chardet
<mark>except</mark> ImportError:
chardet = None
```
然后,你可以用一個簡單的 `if` 語句來檢查 `chardet` 模塊是否存在:
```
if chardet:
# do something
else:
# continue anyway
```
另一個對 `ImportError` 異常的通常使用是當兩個模塊實現了一個公共的 API,但我們更想要其中一個的時候。(可能它速度更快,或者使用了更少的內存。) 你可以試著導入其中一個模塊,并且在這個模塊導入失敗的時候退回到另一個不同的模塊。例如, [XML 的章節](xml.html)談論了兩個模塊實現一個公共的 API,叫做 `ElementTree` API。 第一個,`lxml` 是一個第三方的模塊,你需要自己下載和安裝。第二個, `xml.etree.ElementTree` 比較慢,但屬于 Python 3 標準庫的一部分。
```
try:
from lxml import etree
except ImportError:
import xml.etree.ElementTree as etree
```
在這個 `try..except` 塊的結尾,你導入了_某個_模塊并取名為 `etree`。由于兩個模塊實現了一個公共的 API,你剩下的代碼不需要一直去檢查哪個模塊被導入了。而且由于這個一定會被導入的模塊總是叫做 `etree`,你余下的代碼就不會被調用不同名稱模塊的 `if` 語句所打亂。
## Unbound 變量
再看看 `approximate_size()` 函數里面的這行代碼:
```
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
```
你從不聲明這個 `multiple` 變量,你只是給它賦值了。這樣就可以了,因為 Python 讓你那樣做。 Python 將不會讓你做的是,引用了一個變量,但從不給它賦值。這樣的嘗試將會拋出一個 `NameError` 的異常。
```
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x = 1
>>> x
1
```
將來有一天,你會因為這個而感謝 Python 。
## 所有的東西都是區分大小寫的
Python 里面所有的名稱都是區分大小寫的:變量名、函數名、類名、模塊名稱、異常名稱。如果你可以獲取它、設置它、調用它、構建它、導入它、或者拋出它,那么它就是區分大小寫的。
```
>>> an_integer = 1
>>> an_integer
1
>>> AN_INTEGER
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'AN_INTEGER' is not defined
>>> An_Integer
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'An_Integer' is not defined
>>> an_inteGer
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'an_inteGer' is not defined
```
等等。
## 運行腳本
Python 里面所有東西都是對象。
Python 模塊是對象,并且有幾個有用的屬性。在你編寫它們的時候,通過包含一個特殊的僅在你從命令行運行 Python 文件的時候執行的代碼塊,你可以使用這些屬性容易地測試你的模塊。看看 `humansize.py` 的最后幾行代碼:
```
if __name__ == '__main__':
print(approximate_size(1000000000000, False))
print(approximate_size(1000000000000))
```
> ?像 C 語言一樣, Python 使用 `==` 來做比較,用 `=` 來賦值。不同于 C 語言的是, Python 不支持內嵌的賦值,所以沒有機會出現你本以為在做比較而且意外的寫成賦值的情況。
那么是什么使得這個 `if` 語句特別的呢? 好吧,模塊是對象,并且所有模塊都有一個內置的屬性 `__name__`。一個模塊的 `__name__` 屬性取決于你怎么來使用這個模塊。如果你 `import` 這個模塊,那么 `__name__` 就是這個模塊的文件名,不包含目錄的路徑或者文件的擴展名。
```
>>> import humansize
>>> humansize.__name__
'humansize'
```
但是你也可以當作一個獨立的程序直接運行這個模塊,那樣的話 `__name__` 將是一個特殊的默認值 `__main__`。 Python 將會評估這個 `if` 語句,尋找一個值為 true 的表達式,然后執行這個 `if` 代碼塊。在這個例子中,打印兩個值。
```
c:\home\diveintopython3> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB
```
這就是你的第一個 Python 程序!
## 深入閱讀
* [PEP 257: Docstring 約定](http://www.python.org/dev/peps/pep-0257/)解釋了用什么來從大量的 `docstring` 中分辨出一個好的 `docstring`。
* [Python 教程:文檔字符串](http://docs.python.org/3.1/tutorial/controlflow.html#documentation-strings)也略微提到了這個主題。
* [PEP 8: Python 代碼的風格指南](http://www.python.org/dev/peps/pep-0008/)討論了好的縮進風格。
* [Python 參考手冊](http://docs.python.org/3.1/reference/)解釋了為什么說 Python 里面所有東西都是對象,因為有些人是書呆子,喜歡詳細地討論一些東西。
- 版權信息
- Chapter -1 《深入 Python 3》中有何新內容
- Chapter 0 安裝 Python
- Chapter 1 你的第一個 Python 程序
- Chapter 2 內置數據類型
- Chapter 3 解析
- Chapter 4 字符串
- Chapter 5 正則表達式
- Chapter 6 閉合 與 生成器
- Chapter 7 類 & 迭代器
- Chapter 8 高級迭代器
- Chapter 9 單元測試
- Chapter 10 重構
- Chapter 11 文件
- Chapter 12 XML
- Chapter 13 序列化Python對象
- Chapter 14 HTTP Web 服務
- Chapter 15 案例研究:將chardet移植到Python 3
- Chapter 16 打包 Python 類庫
- Chapter A 使用2to3將代碼移植到Python 3
- Chapter B 特殊方法名稱
- Chapter C 接下來閱讀什么?