| 導航:起始頁 > Dive Into Python > 技巧和竅門 | << >> | ||||
深入 Python :Dive Into Python 中文版Python 從新手到專家 [Dip_5.4b_CPyUG_Release] |
|||||
| 在 Windows 的 ActivePython IDE 中,可以選擇 -> (Ctrl-R) 來運行 Python 程序。輸出結果將顯示在交互窗口中。 | |
| 在 Mac OS 的 Python IDE 中,可以選擇 -> (Cmd-R) 來運行 Python 程序,但首先要設置一個重要的選項。在 IDE 中打開 .py 模塊,點擊窗口右上角的黑色三角,彈出這個模塊的選項菜單,然后將 選中。 這個設置是同模塊一同保存的,所以對于每個模塊您都需要這樣做。 | |
| 在 UNIX 兼容的操作系統中 (包括 Mac OS X),可以通過命令行:python odbchelper.py 運行模塊。 | |
| 在 Visual Basic 中,函數 (有返回值) 以 function 開始,而子程序 (無返回值) 以 sub 開始。在 Python 中沒有子程序。只有函數,所有的函數都有返回值 (盡管可能為 None),并且所有的函數都以 def 開始。 | |
| 在 Java、C++ 和其他靜態類型語言中,必須要指定函數返回值和每個函數參數的數據類型。在 Python 中,永遠也不需要明確指定任何東西的數據類型。Python 會根據賦給它的值在內部將其數據類型記錄下來。 | |
| 三重引號也是一種定義既包含單引號又包含雙引號的字符串的簡單方法,就像 Perl 中的 qq/.../ 。 | |
| 許多 Python IDE 使用 doc string 來提供上下文敏感的文檔信息,所以當鍵入一個函數名時,它的 doc string 顯示為一個工具提示。這一點可以說非常有用,但是它的好壞取決于您書寫的 doc string 的好壞。 | |
| 在 Python 中的 import 就像 Perl 中的 require。import 一個 Python 模塊后,您就可以使用 module.function 來訪問它的函數;require 一個 Perl 模塊后,您就可以使用 module::function 來訪問它的函數。 | |
| Python 使用硬回車來分割語句,冒號和縮進來分割代碼塊。C++ 和 Java 使用分號來分割語句,花括號來分割代碼塊。 | |
| 與 C 一樣,Python 使用 == 做比較,使用 = 做賦值。與 C 不一樣,Python 不支持行內賦值,所以不會出現想要進行比較卻意外地出現賦值的情況。 | |
| 在 MacPython 上,需要一個額外的步聚來使得 if __name__ 技巧有效。點擊窗口右上角的黑色三角,彈出模塊的屬性菜單,確認 被選中。 | |
| Python 中的 dictionary 就像 Perl 中的 hash (哈希數組)。在 Perl 中,存儲哈希值的變量總是以 % 字符開始;在 Python 中,變量可以任意取名,并且 Python 在內部會記錄下其數據類型。 | |
| Python 中的 dictionary 像 Java 中的 Hashtable 類的實例。 | |
| Python 中的 dictionary 像 Visual Basic 中的 Scripting.Dictionary 對象的實例。 | |
| Dictionary 沒有元素順序的概念。說元素 “順序亂了” 是不正確的,它們只是序偶的簡單排列。這是一個重要的特性,它會在您想要以一種特定的,可重現的順序 (像以 key 的字母表順序) 存取 dictionary 元素的時候騷擾您。有一些實現這些要求的方法,它們只是沒有加到 dictionary 中去。 | |
| Python 的 list 如同 Perl 中的數組。在 Perl 中,用來保存數組的變量總是以 @ 字符開始;在 Python 中,變量可以任意取名,并且 Python 在內部會記錄下其數據類型。 | |
| Python 中的 list 更像 Java 中的數組 (您可以簡單地這樣理解,但 Python 中的 list 遠比 Java 中的數組強大)。一個更好的類比是 ArrayList 類,它可以保存任意對象,并且可以在增加新元素時動態擴展。 | |
在 2.2.1 版本之前,Python 沒有單獨的布爾數據類型。為了彌補這個缺陷,Python 在布爾環境 (如 if 語句) 中幾乎接受所有東西,遵循下面的規則:
|
|
| Tuple 可以轉換成 list,反之亦然。內置的 tuple 函數接收一個 list,并返回一個有著相同元素的 tuple。而 list 函數接收一個 tuple 返回一個 list。從效果上看,tuple 凍結一個 list,而 list 解凍一個 tuple。 | |
| 當一條命令用續行符 (“\”) 分割成多行時,后續的行可以以任何方式縮進,此時 Python 通常的嚴格的縮進規則無需遵守。如果您的 Python IDE 自由對后續行進行了縮進,您應該把它當成是缺省處理,除非您有特別的原因不這么做。 | |
| 在 Python 中,字符串格式化使用與 C 中 sprintf 函數一樣的語法。 | |
| join 只能用于元素是字符串的 list;它不進行任何的強制類型轉換。連接一個存在一個或多個非字符串元素的 list 將引發一個異常。 | |
| anystring.split(delimiter, 1) 是一個有用的技術,在您想要搜索一個子串,然后分別處理字符前半部分 (即 list 中第一個元素) 和后半部分 (即 list 中第二個元素) 時,使用這個技術。 | |
| 調用函數時唯一必須做的事情就是為每一個必備參數指定值 (以某種方式);以何種具體的方式和順序都取決于你。 | |
| Python 提供了很多出色的參考手冊,你應該好好地精讀一下所有 Python 提供的必備模塊。對于其它大部分語言,你會發現自己要常常回頭參考手冊或者 man 頁來提醒自己如何使用這些模塊,但是 Python 不同于此,它很大程度上是自文檔化的。 | |
| lambda 函數是一種風格問題。不一定非要使用它們;任何能夠使用它們的地方,都可以定義一個單獨的普通函數來進行替換。我將它們用在需要封裝特殊的、非重用代碼上,避免令我的代碼充斥著大量單行函數。 | |
| 在 SQL 中,你必須使用 IS NULL 代替 = NULL 進行 null 值比較。在 Python,你可以使用 == None 或者 is None 進行比較,但是 is None 更快。 | |
| Python 中的 from module import * 像 Perl 中的 use module ;Python 中的 import module 像 Perl 中的 require module 。 | |
| Python 中的 from module import * 像 Java 中的 import module.* ;Python 中的 import module 像 Java 中的 import module 。 | |
| 盡量少用 from module import * ,因為判定一個特殊的函數或屬性是從哪來的有些困難,并且會造成調試和重構都更困難。 | |
| 在 Python 中的 pass 語句就像 Java 或 C 中的大括號空集 ({})。 | |
| 在 Python 中,類的基類只是簡單地列在類名后面的小括號里。不像在 Java 中有一個特殊的 extends 關鍵字。 | |
| 習慣上,任何 Python 類方法的第一個參數 (對當前實例的引用) 都叫做 self。這個參數扮演著 C++ 或 Java 中的保留字 this 的角色,但 self 在 Python 中并不是一個保留字,它只是一個命名習慣。雖然如此,也請除了 self 之外不要使用其它的名字,這是一個非常堅固的習慣。 | |
| __init__ 方法是可選的,但是一旦你定義了,就必須記得顯示調用父類的 __init__ 方法 (如果它定義了的話)。這樣更是正確的:無論何時子類想擴展父類的行為,后代方法必須在適當的時機,使用適當的參數,顯式調用父類方法。 | |
| 在 Python 中,創建類的實例只要調用一個類,仿佛它是一個函數就行了。不像 C++ 或 Java 有一個明確的 new 操作符。 | |
| 在 Windows 下的 ActivePython IDE 中,你可以快速打開在你的庫路徑中的任何模塊,使用 -> (Ctrl-L)。 | |
| Java 和 Powerbuilder 支持通過參數列表的重載,也就是 一個類可以有同名的多個方法,但這些方法或者是參數個數不同,或者是參數的類型不同。其它語言 (最明顯如 PL/SQL) 甚至支持通過參數名的重載,也就是 一個類可以有同名的多個方法,這些方法有相同類型,相同個數的參數,但參數名不同。Python 兩種都不支持,總之是沒有任何形式的函數重載。一個 __init__ 方法就是一個 __init__ 方法,不管它有什么樣的參數。每個類只能有一個 __init__ 方法,并且如果一個子類擁有一個 __init__ 方法,它總是 覆蓋父類的 __init__ 方法,甚至子類可以用不同的參數列表來定義它。 | |
| Python 的原作者 Guido 是這樣解釋方法覆蓋的:“子類可以覆蓋父類中的方法。因為方法沒有特殊的優先級設置,父類中的一個方法在調用同類中的另一方法時,可能其實調用到的卻是一個子類中覆蓋父類同名方法的方法。 (C++ 程序員可能會這樣想:所有的 Python 方法都是虛函數。)”如果你不明白 (它令我頗感困惑),不必在意。我想我要跳過它。[3] | |
| 應該總是在 __init__ 方法中給一個實例的所有數據屬性賦予一個初始值。這樣做將會節省你在后面調試的時間,不必為捕捉因使用未初始化 (也就是不存在) 的屬性而導致的 AttributeError 異常費時費力。 | |
| 在 Python 2.2 之前的版本中,你不可以直接子類化字符串、列表以及字典之類的內建數據類型。作為補償,Python 提供封裝類來模擬內建數據類型的行為,比如:UserString、UserList 和 UserDict。通過混合使用普通和特殊方法,UserDict 類能十分出色地模仿字典。在 Python 2.2 和其后的版本中,你可以直接從 dict 內建數據類型繼承。本書 fileinfo_fromdict.py 中有這方面的一個例子。 | |
| 當在一個類中存取數據屬性時,你需要限定屬性名:self.attribute。當調用類中的其它方法時,你屬要限定方法名:self.method。 | |
| 在 Java 中,通過使用 str1 == str2 可以確定兩個字符串變量是否指向同一塊物理內存位置。這叫做對象同一性,在 Python 中寫為 str1 is str2。在 Java 中要比較兩個字符串值,你要使用 str1.equals(str2);在 Python 中,你要使用 str1 == str2。某些 Java 程序員,他們已經被教授得認為,正是因為在 Java 中 == 是通過同一性而不是值進行比較,所以世界才會更美好。這些人要接受 Python 的這個“嚴重缺失”可能要花些時間。 | |
| 其它的面向對象語言僅讓你定義一個對象的物理模型 (“這個對象有 GetLength 方法”),而 Python 的專用類方法像 __len__ 允許你定義一個對象的邏輯模型 (“這個對象有一個長度”)。 | |
| 在 Java 中,靜態變量 (在 Python 中叫類屬性) 和實例變量 (在 Python 中叫數據屬性) 兩者都是緊跟在類定義之后定義的 (一個有 static 關鍵字,一個沒有)。在 Python 中,只有類屬性可以定義在這里,數據屬性定義在 __init__ 方法中。 | |
| 在 Python 中沒有常量。如果你試圖努力的話什么都可以改變。這一點滿足 Python 的核心原則之一:壞的行為應該被克服而不是被取締。如果你真正想改變 None 的值,也可以做到,但當無法調試的時候別來找我。 | |
| 在 Python 中,所有的專用方法 (像 __setitem__) 和內置屬性 (像 __doc__) 遵守一個標準的命名習慣:開始和結束都有兩個下劃線。不要對你自已的方法和屬性用這種方法命名;到最后,它只會把你 (或其它人) 搞亂。 | |
| Python 使用 try...except 來處理異常,使用 raise 來引發異常。Java 和 C++ 使用 try...catch 來處理異常,使用 throw 來引發異常。 | |
| 只要有可能,你就應該使用在 os 和 os.path 中的函數進行文件、目錄和路徑的操作。這些模塊是對平臺相關模塊的封裝模塊,所以像 os.path.split 這樣的函數可以工作在 UNIX、Windows、Mac OS 和 Python 所支持的任一種平臺上。 | |
| 沒有一個輕松的方法來確定兩個正則表達式是否等價。你能采用的最好的辦法就是列出很多的測試樣例,確定這兩個正則表達式對所有的相關輸入都有相同的輸出。在本書后面的章節,將更多地討論如何編寫測試樣例。 | |
| Python 2.0 存在一個 bug,即 SGMLParser 完全不能識別聲明 (handle_decl 永遠不會調用),這就意味著 DOCTYPE 被靜靜地忽略掉了。這個錯誤在 Python 2.1 中改正了。 | |
| 在 Windows 下的 ActivePython IDE 中,您可以在 “Run script” 對話框中指定命令行參數。用空格將多個參數分開。 | |
| HTML 規范要求所有非 HTML (像客戶端的 JavaScript) 必須包括在 HTML 注釋中,但不是所有的頁面都是這么做的 (而且所有的最新的瀏覽器也都容許不這樣做) 。BaseHTMLProcessor 不允許這樣,如果腳本嵌入得不正確,它將被當作 HTML 一樣進行分析。例如,如果腳本包含了小于和等于號,SGMLParser 可能會錯誤地認為找到了標記和屬性。SGMLParser 總是把標記名和屬性名轉換成小寫,這樣可能破壞了腳本,并且 BaseHTMLProcessor 總是用雙引號來將屬性封閉起來 (盡管原始的 HTML 文檔可能使用單引號或沒有引號) ,這樣必然會破壞腳本。應該總是將您的客戶端腳本放在 HTML 注釋中進行保護。 | |
Python 2.2 引入了一種略有不同但重要的改變,它會影響名字空間的搜索順序:嵌套的作用域。
在 Python 2.2 版本之前,當您在一個嵌套函數或 lambda 函數中引用一個變量時,Python 會在當前 (嵌套的或 lambda) 函數的名字空間中搜索,然后在模塊的名字空間。Python 2.2 將只在當前 (嵌套的或 lambda) 函數的名字空間中搜索,然后是在父函數的名字空間 中搜索,接著是模塊的名字空間中搜索。Python 2.1 可 以兩種方式工作,缺省地,按 Python 2.0 的方式工作。但是您可以把下面一行代碼增加到您的模塊頭部,使您的模塊工作起來像 Python 2.2 的方式:from __future__ import nested_scopes |
|
| 使用 locals 和 globals 函數,通過提供變量的字符串名字您可以動態地得到任何變量的值。這種方法提供了這樣的功能:getattr 函數允許您通過提供函數的字符串名來動態地訪問任意的函數。 | |
| 使用 locals 來應用基于 dictionary 的字符串格式化是一種方便的作法,它可以使復雜的字符串格式化表達式更易讀。但它需要花費一定的代價。在調用 locals 方面有一點性能上的問題,這是由于 locals 創建了局部名字空間的一個拷貝引起的。 | |
| 一個包是一個其中帶有特殊文件 __init__.py 的目錄。__init__.py 文件定義了包的屬性和方法。其實它可以什么也不定義;可以只是一個空文件,但是必須要存在。如果 __init__.py 不存在,這個目錄就僅僅是一個目錄,而不是一個包,它就不能被導入或者包含其它的模塊和嵌套包。 | |
| 這部分由于某個含義重疊的術語可能讓人有點糊涂。在一個 XML 文檔中,元素可以有屬性,而 Python 對象也有屬性。當你解析一個 XML 文檔時,你得到了一組 Python 對象,它們代表 XML 文檔中的所有片段,同時有些 Python 對象代表 XML 元素的屬性。但是表示 (XML) 屬性的 (Python) 對象也有 (Python) 屬性,它們用于訪問對象表示的 (XML) 屬性。我告訴過你它讓人糊涂。我會公開提出關于如何更明顯地區分這些不同的建議。 | |
| 類似于字典,一個 XML 元素的屬性沒有順序。屬性可以以某種順序偶然 列在最初的 XML 文檔中,而在 XML 文檔解析為 Python 對象時,Attr 對象以某種順序偶然 列出,這些順序都是任意的,沒有任何特別的含義。你應該總是使用名稱來訪問單個屬性,就像字典的鍵一樣。 | |
| 在這些例子中,HTTP 服務器同時支持 Last-Modified 和 ETag 頭信息,但并非所有的服務器皆如此。作為一個 web 服務的客戶端,你應該為支持兩種頭信息做準備,但是你的程序也應該為服務器僅支持其中一種頭信息或兩種頭信息都不支持而做準備。 | |
| Python 2.1 和之后的版本已經包含了 unittest。Python 2.0 用戶則可以從 pyunit.sourceforge.net下載。 | |
| 全面的單元測試能夠告訴你的最重要的事情是什么時候停止編寫代碼。當一個函數的所有單元測試都通過了,停止編寫這個函數。一旦整個模塊的單元測試通過了,停止編寫這個模塊。 | |
| 當所有測試都通過了,停止編程。 | |
| 在需要多次使用同一個正則表達式的情況下,應該將它進行編譯以獲得一個 pattern 對象,然后直接調用這個 pattern 對象的方法。 | |
| 傳遞給 os.path.abspath 的路徑名和文件名可以不存在。 | |
| os.path.abspath 不僅構建完整路徑名,還能格式化路徑名。這意味著如果你正工作于 /usr/ 目錄,os.path.abspath('bin/../local/bin') 將會返回 /usr/local/bin。它把路徑名格式化為盡可能簡單的形式。如果你只是希望簡單地返回這樣的格式化路徑名而不需要完整路徑名,可以使用 os.path.normpath。 | |
| 就像 os 和 os.path 模塊的其他函數,os.path.abspath 是跨平臺的。如果你是在 Windows (使用反斜杠作為路徑符號) 或 Mac OS (使用冒號) 上運行,它們同樣工作,只是將獲得與我稍有不同的結果。os 的所有函數都是這樣的。 | |
| 你可以在命令行使用 timeit 模塊來測試一個已存在的 Python 程序,而不需要修改代碼。在 http://docs.python.org/lib/node396.html 查看文檔中關于命令行選項的內容。 | |
| timeit 模塊只有在你知道哪段代碼需要優化時使用。如果你有一個很大的 Python 程序并且不知道你的性能問題所在,查看 hotshot 模塊。 | |
<< 五分鐘回顧 |
| | |
示例清單 >> |