Pythonic的定義
遵循Pythonic的代碼,看起來就像是偽代碼,所有的偽代碼都可以輕易轉(zhuǎn)換為可執(zhí)行的Python代碼。比如在Wikipedia的快速排序條目下有如下偽代碼:
function quicksort('array')
if length('array') < 1
return 'array'
for each 'x' in 'array'
if 'x' <= 'pivot' then append 'x' to 'less'
else append 'x' to 'greater'
return concatenate(quicksort('less'), list('pivot'), quicksort('greater'))
實(shí)際上,它可以轉(zhuǎn)化為以下同等行數(shù)的可以執(zhí)行的Python代碼:
def quicksort(array):
less = []
greater =[]
if len(array) <= 1:
return array
pivot = array.pop()
for x in array:
if x <= pivot:
less.append(x)
else:
greater.append(x)
return quicksort(less) + [pivot] + quicksort(greater)
綜合這個例子來說,Pythonic也許可以定義為:充分體現(xiàn)Python自身特色的代碼風(fēng)格。
代碼風(fēng)格
對于風(fēng)格,光說是沒有用的,最好是通過例子來看看,因?yàn)槔涌吹囊姡瑫@得真實(shí),下面以語法,庫和應(yīng)用程序?yàn)槔o大家介紹
在語法上,代碼風(fēng)格要充分體現(xiàn)Python自身特色。舉個最常見的例子,在其他語言中,兩個變量交換需要如下的代碼:
int a=1, b=2;
int tmp =a;
a=b;
b=tmp;
利用Python的packaging/unpackaging機(jī)制,Pythonic的代碼只需下一行:
a, b = b, a
還有,在遍歷一個容器的時候,類似其他編程語言的代碼如下:
length = len(alist)
i =0
while i < length:
do_sth_with(alist[i])
i += 1
而Pythonic的代碼如下:
for i in alist:
do_sth_with(i)
靈活的使用迭代器也是一種Python風(fēng)格,又比如,需要安全的關(guān)閉文件描述符,可以使用一下with語句:
with open(path, 'r') as f:
do_sth_with(f)
通過上述的代碼的對比,大家能夠清晰的認(rèn)識到Pythonic的一個要求,就是對Python語法本身的充分的發(fā)揮,寫出來的代碼都是帶著Python
味兒,而不是看著像C語言的代碼,或者像Java代碼
應(yīng)當(dāng)追求的是充分利用Python語法,但不應(yīng)當(dāng)過分的使用奇技淫巧,比如利用Python的Slice語法,可以下廚如下代碼:
a=[1,2,3,4]
c = 'abcdef'
print a[::-1]
print c[::-1]
如果不是同樣追求每一個語法細(xì)節(jié)的老鳥,這段代碼的作用恐怕不能一眼看出來。這個時候更好的體現(xiàn)Pythonic的代碼是充分利用Python庫里的reversed()函數(shù)的代碼
print list(reversed(a))
print list(reversed(c))
標(biāo)準(zhǔn)庫
寫Pythonic程序需要對標(biāo)準(zhǔn)庫有充分的理解,特別是內(nèi)置函數(shù)和內(nèi)置數(shù)據(jù)類型。比如,對于字符串格式化,一般這樣寫:
print 'hello %s' % ('Tom',)
其實(shí)%s是非常影響可讀性的,因?yàn)閿?shù)量多了以后,很難清楚哪一個占位符對應(yīng)哪一個實(shí)參。所以相對應(yīng)的Pythonic代碼是這樣的:
print 'hello %(name)s' %('name': 'Tom')
這樣在參數(shù)比較多的情況下尤其有用
# 字符串
value = {'greet': 'helo world', 'language': 'Python'}
print '%(greet)s from %(language)s.' % value
%占位符來自于大家的先驗(yàn)只是,其實(shí)對于新手而言,有點(diǎn)莫名其妙,所以更具Pythonic風(fēng)格的代碼如下:
print '{greet} from {language}'.format(greet='hello world', language='Python')
str.format()方法非常清晰地表達(dá)了這條語句的意圖,而且模板的使用也減少了許多不必要的字符,使可讀性得到了很大提升。事實(shí)上,str.format()也成了Python最為推薦的字符串格式化方法,當(dāng)然也是最Pythonic的
Pythonic的庫或框架
編寫應(yīng)用程序的時候的要求會更高一些。因?yàn)榫帉憫?yīng)用程序一般需要團(tuán)隊合作,那么可能你編寫的那一部分正好是團(tuán)隊的另一成員需要調(diào)用的接口,換言之,你可能正在編寫庫或框架
程序員利用Pythonic的庫或框架能更加容易,更加自然的完成任務(wù)。如果利用Python編寫的庫或框架迫使程序員編寫累贅的或不推薦的代碼,那么可以說它并不Pythonic。現(xiàn)在業(yè)內(nèi)通常認(rèn)為Flask這個框架是比較Pythonic的,它的一個hello world級別的用例如下:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'hello world'
if __name__ == '__main__':
app.run()
稍有編程經(jīng)驗(yàn)的人都可以通過上例認(rèn)識到利用Python編程極為容易這一事實(shí)。一個Pythonic的框架不會對已經(jīng)通過慣用法完成的東西重復(fù)發(fā)明“”輪子“,而且它頁遵循常用的Python慣例。創(chuàng)建Pythonic的框架及其困難,什么理念更酷,更符合語言習(xí)慣對此毫無幫助,事實(shí)上這些年來優(yōu)秀的Python代碼的特性也在不斷演化。比如現(xiàn)在認(rèn)為像generators之類的特性尤為Pythonic
另一個有關(guān)新趨勢的例子是:Python的包和模塊結(jié)構(gòu)日益規(guī)范化。現(xiàn)在的庫或框架跟隨了以下潮流:
- 包和模塊的命名才用小寫,單數(shù)形式,而且短小
- 包通常僅作為命名空間,如只包含空的init.py文件