竅門壹:關鍵代碼使用外部功能包
Python簡化了許多編程任務,但是對於壹些時間敏感的任務,它的表現經常不盡人意。使用C/C++或機器語言的外部功能包處理時間敏感任務,可以有效提高應用的運行效率。這些功能包往往依附於特定的平臺,因此妳要根據自己所用的平臺選擇合適的功能包。簡而言之,這個竅門要妳犧牲應用的可移植性以換取只有通過對底層主機的直接編程才能獲得的運行效率。以下是壹些妳可以選擇用來提升效率的功能包:
Cython
Pylnlne
PyPy
Pyrex
這些功能包的用處各有不同。比如說,使用C語言的數據類型,可以使涉及內存操作的任務更高效或者更直觀。Pyrex就能幫助Python延展出這樣的功能。Pylnline能使妳在Python應用中直接使用C代碼。內聯代碼是獨立編譯的,但是它把所有編譯文件都保存在某處,並能充分利用C語言提供的高效率。
竅門二:在排序時使用鍵
Python含有許多古老的排序規則,這些規則在妳創建定制的排序方法時會占用很多時間,而這些排序方法運行時也會拖延程序實際的運行速度。最佳的排序方法其實是盡可能多地使用鍵和內置的sort()方法。譬如,拿下面的代碼來說:
import operator
somelist = [(1, 5,?, (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(0))
somelist
#Output = [(1, 5,?, (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(1))
somelist
#Output = [(6, 2, 4), (1, 5,?, (9, 7, 5)]
somelist.sort(key=operator.itemgetter(2))
somelist
#Output = [(6, 2, 4), (9, 7, 5), (1, 5,?]
在每段例子裏,list都是根據妳選擇的用作關鍵參數的索引進行排序的。這個方法不僅對數值類型有效,還同樣適用於字符串類型。
竅門三:針對循環的優化
每壹種編程語言都強調最優化的循環方案。當使用Python時,妳可以借助豐富的技巧讓循環程序跑得更快。然而,開發者們經常遺忘的壹個技巧是:盡量避免在循環中訪問變量的屬性。譬如,拿下面的代碼來說:
lowerlist = ['this', 'is', 'lowercase']
upper = str.upper
upperlist = []
append = upperlist.append
for word in lowerlist:
append(upper(word))
print(upperlist)
#Output = ['THIS', 'IS', 'LOWERCASE']
每次妳調用str.upper, Python都會計算這個式子的值。然而,如果妳把這個求值賦值給壹個變量,那麽求值的結果就能提前知道,Python程序就能運行得更快。因此,關鍵就是盡可能減小Python在循環中的工作量。因為Python解釋執行的特性,在上面的例子中會大大減慢它的速度。
(註意:優化循環的方法還有很多,這只是其中之壹。比如,很多程序員會認為,列表推導式是提高循環速度的最佳方法。關鍵在於,優化循環方案是提高應用程序運行速度的上佳選擇。)
竅門四:使用較新的Python版本
如果妳在網上搜索Python,妳會發現數不盡的信息都是關於如何升級Python版本。通常,每個版本的Python都會包含優化內容,使其運行速度優於之前的版本。但是,限制因素在於,妳最喜歡的函數庫有沒有同步更新支持新的Python版本。與其爭論函數庫是否應該更新,關鍵在於新的Python版本是否足夠高效來支持這壹更新。
妳要保證自己的代碼在新版本裏還能運行。妳需要使用新的函數庫才能體驗新的Python版本,然後妳需要在做出關鍵性的改動時檢查自己的應用。只有當妳完成必要的修正之後,妳才能體會新版本的不同。
然而,如果妳只是確保自己的應用在新版本中可以運行,妳很可能會錯過新版本提供的新特性。壹旦妳決定更新,請分析妳的應用在新版本下的表現,並檢查可能出問題的部分,然後優先針對這些部分應用新版本的特性。只有這樣,用戶才能在更新之初就覺察到應用性能的改觀。
竅門五:嘗試多種編碼方法
每次創建應用時都使用同壹種編碼方法幾乎無壹例外會導致應用的運行效率不盡人意。可以在程序分析時嘗試壹些試驗性的辦法。譬如說,在處理字典中的數據項時,妳既可以使用安全的方法,先確保數據項已經存在再進行更新,也可以直接對數據項進行更新,把不存在的數據項作為特例分開處理。請看下面第壹段代碼:
n = 16
myDict = {}
for i in range(0, n):
char = 'abcd'[i%4]
if char not in myDict:
myDict[char] = 0
myDict[char] += 1
print(myDict)
當壹開始myDict為空時,這段代碼會跑得比較快。然而,通常情況下,myDict填滿了數據,至少填有大部分數據,這時換另壹種方法會更有效率。
n = 16
myDict = {}
for i in range(0, n):
char = 'abcd'[i%4]
try:
myDict[char] += 1
except KeyError:
myDict[char] = 1
print(myDict)
在兩種方法中輸出結果都是壹樣的。區別在於輸出是如何獲得的。跳出常規的思維模式,創建新的編程技巧能使妳的應用更有效率。
竅門六:交叉編譯妳的應用
開發者有時會忘記計算機其實並不理解用來創建現代應用程序的編程語言。計算機理解的是機器語言。為了運行妳的應用,妳借助壹個應用將妳所編的人類可讀的代碼轉換成機器可讀的代碼。有時,妳用壹種諸如Python這樣的語言編寫應用,再以C++這樣的語言運行妳的應用,這在運行的角度來說,是可行的。關鍵在於,妳想妳的應用完成什麽事情,而妳的主機系統能提供什麽樣的資源。
Nuitka是壹款有趣的交叉編譯器,能將妳的Python代碼轉化成C++代碼。這樣,妳就可以在native模式下執行自己的應用,而無需依賴於解釋器程序。妳會發現自己的應用運行效率有了較大的提高,但是這會因平臺和任務的差異而有所不同。
(註意:Nuitka現在還處在測試階段,所以在實際應用中請多加註意。實際上,當下最好還是把它用於實驗。此外,關於交叉編譯是否為提高運行效率的最佳方法還存在討論的空間。開發者已經使用交叉編譯多年,用來提高應用的速度。記住,每壹種解決辦法都有利有弊,在把它用於生產環境之前請仔細權衡。)
在使用交叉編譯器時,記得確保它支持妳所用的Python版本。Nuitka支持Python2.6, 2.7, 3.2和3.3。為了讓解決方案生效,妳需要壹個Python解釋器和壹個C++編譯器。Nuitka支持許多C++編譯器,其中包括Microsoft Visual Studio,MinGW 和 Clang/LLVM。
交叉編譯可能造成壹些嚴重問題。比如,在使用Nuitka時,妳會發現即便是壹個小程序也會消耗巨大的驅動空間。因為Nuitka借助壹系列的動態鏈接庫(DDLs)來執行Python的功能。因此,如果妳用的是壹個資源很有限的系統,這種方法或許不太可行。