分享書籍[writing idiomatic python ebook]


你是不是總是覺得學了python好久,驀然回首,總是感覺寫的代碼不是那么有pythonic的味道。看看別人的代碼(django,webpy),再看看自己的代碼,覺得就是一java-python的混合體。鑒於這種問題,我准備要多學習別人的一些技術和方式,這不,在網上看到一本不錯的書:[writing idiomatic python ebook] 。告訴怎么寫出python風格的代碼。本來想共享到網盤的,但是一想,這樣不好吧,人家的書是掛在上面付費賣的,也不貴,10刀。所以就不共享了。這里把里面的一些注意點以筆記的形式分享出來一起學習。

ps:我今天發現在163網易閱讀里有這本書,提供下鏈接:http://yuedu.163.com/source/cl_dc23b96c2df84533957ffb1089e90604_4

在if語句中用鏈式比較使之更簡明

x = 5
if x > 1 and x < 6:
    print 'python'

改成:

if 1 < x < 6:
    print 'python'

 

不要在if語句后面直接寫代碼,而是換行 

x = True
if x:print 'python'
print 'is great!'

改成:

x = True
if x:
    print 'python'
print 'is great!'

  

在條件判斷時,應該避免直接和True,False,None進行比較(==)

比如我們判斷一個集合為空是,會這樣寫:

l = []
if l == []:
    print 'l is empty list'

改成:

l = []
if not l:
    print 'l is empty list'

其實在if語條的條件判斷時,我們一般的語境上下文還是很明確,如對象是否為None,是否條件為True,或者集合是否為空,字典是否為空。python支持直接在if后台跟着這些對象,自動為根據語境轉換為相應的布爾值(True或False)。 滿足如下的情況,都會認為是False:

  1. None
  2. False
  3. 為0的數值型實例(number)
  4. 空的序列,如list, tuple
  5. 空的字典,如dict
  6. 在自定義的類中定義了__len__返回0 ,或者定義了__nonzero__返回False

但是有些情況還是不同的,不能適用於這個規則。看下面一個實例:

def getCurrentPositon(position=None):
    if not position:
        print 'you must set you current position!'

getCurrentPositon(0)   

方法的作用是得到根據傳入的位置做相應的工作。如果傳入參數0應該也是合理值,即在坐標原點位置。但是方法還是會打印'you must set you current position!'。 因為0值被條件判斷為False。所以應該改成如下 :

def getCurrentPositon(position=None):
    if position is None:
        print 'you must set you current position!'

getCurrentPositon(0)

顯示的比較是否為None,而不依賴內建的布爾轉換。注意這里是用 is 操作符沒有用 == 比較符。因為None對象在python中是單實例的,而is就是直接比較兩個對象是否一樣(可以理解占用同一條內存)

 

用if,else替換三元(ternary)運算操作符

flag = 2

if flag == 1:
    displayValue = 'man'
elif flag == 2:
    displayValue = 'woman'

改成:

displayValue = 'man' if flag == 1 else 'woman'

 

用enumerate函數代替for循環中的index變量訪問

my_container = ['lily', 'lucy', 'tom']
index = 0
for element in my_container:
    print '{} {}'.format(index, element)
    index += 1

改成:

for index, element in enumerate(my_container):
    print '%d %s' % (index, element)

 

當for循環體執行完后,可以用else去執行相關的動作

如這樣的場景:遍歷所有人的年齡信息,決斷當前所有人是不是都是成年人,假如以大於等於20歲划分:

all_person_age = [21, 22, 23, 30]

is_all_adult = True
for age in all_person_age:
    if age <= 20:
        is_all_adult = False
        break

if is_all_adult:
    print 'Tha all are audlt!'

我們這里加了一個 is_all_adult 的標志變量,在循環體中當有年齡小於20歲的人時,把該變量重新置值, 並跳出循環體。我們可以改成 for ... else 的句式,這樣可以省略定義一個標志變量:

all_person_age = [21, 22, 23, 32]

for age in all_person_age:
    if age <= 20:
        break
else:
    print 'Tha all are audlt!'

for...else...的用法就是當for中途退出循環時(沒有遍歷所有的集合元素)時就不執行else里的語句,反之則執行。

 

避免用可變的對象(mutable)作為函數參數中的默認初始化值

def function(l = []):
    l.append(1)
    return l

print function()
print function()
print function()   

將會打印:

[1]
[1, 1]
[1, 1, 1]
[Finished in 0.0s]

這是因為參數的默認初始值只有在定義的時候執行一次,即是單實例的。以后的每一次調用都會用這個對象。改成:

def function(l = None):
    if l is None:
        l = []
    l.append(1)
    return l

 

盡量少定義一些只是用於存儲返回值的變量

def all_equal(a, b, c):
    result = False
    if a == b == c:
        result = True
    return result

改成:

def all_equal(a, b, c):
    return a == b == c

 

試着把函數當成對象實例來用,無論是參數傳入還是返回值

def print_addition_table():
    for x in range(1, 3):
        for y in range(1, 3):
            print(str(x + y) + '\n')

def print_subtraction_table():
    for x in range(1, 3):
        for y in range(1, 3):
            print(str(x - y) + '\n')

def print_multiplication_table():
        for x in range(1, 3):
            for y in range(1, 3):
                print(str(x * y) + '\n')

def print_division_table():
    for x in range(1, 3):
        for y in range(1, 3):
            print(str(x / y) + '\n')

print_addition_table()
print_subtraction_table()
print_multiplication_table()
print_division_table()

像上面的定義的四個函數,基本結構一樣,只是里面進行的運算不同而也(+, -, *, /),我們可以把運算的函數直接作為參數傳遞進去即可:

import operator as op

def print_table(operator):
    for x in range(1, 3):
        for y in range(1, 3):
            print(str(operator(x, y)) + '\n')

for operator in (op.add, op.sub, op.mul, op.div):
    print_table(operator)

在python世界里,一切都是對象,Function也是

 

多用EAFP,少用LBYL

EAFP:easier to ask forgiveness than permission

LBYL:look before you leap

EAFP可以理解成一切按正常的邏輯編碼,不用管可能出現的錯誤,等出了錯誤再說;而LBYL就是盡可能每寫一行代碼,都要提前考慮下當前的前置條件是否成立;

LBYL代碼風格:

def getPersonInfo(person):
    if person == None:
        print 'person must be not null!'
    print person.info 

EAFP代碼風格:

def getPersonInfo(person):
    try:
        print person.info 
    except NameError:
        print 'person must be not null!'

其實用EAFP風格的代碼最大的好處是代碼邏輯清晰,而LBYL會導致本來兩句話說清楚的事,往往因為穿插了很多條件檢查的語句使代碼邏輯變得混亂。

 

不要一根筋似的看到異常就catch並吃掉(swallowing)

如下定義一個方法,請求url並返回響應:

import requests
def get_json_response(url):
    try:
        r = requests.get(url)
        return r.json()
    except:
        print('Oops, something went wrong!')
        return None

如果這個函數給第三方調用,萬一出了什么問題,用戶只會得到一個something went wrong提示,而只能猜出錯的原因,是GFW的問題呢,還是url地址格式錯誤呢。改成如下:

import requests
def get_json_response(url):
    return requests.get(url).json()

把出錯的處理權力交給調用方。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM