如何優雅的寫好python代碼?


Python與其他語言(比如 java或者 C ++ )相比有較大的區別,其中最大的特點就是非常簡潔,如果按照其他語言的思路老師寫Python代碼,則會使得代碼繁瑣復雜,並且容易出現bug,在Python中,有個詞很火,Pythonic。有的同學可能不明白這個詞的意義,小編的理解就是有Python的寫法寫代碼,而非是其他語言的通用寫法,寫出python的特點,寫出Ppython的風格。

下面,就通過幾個示例來看看一下不同思維的Python代碼的差異。

1、變量值的交換

這個詞最常見,大家從最開始寫java及C++等語言代碼都會遇到這個問題,通過一個臨時變量來實現的“:

tmp = a
a = b
b = tmp

而Python中可以之間交換兩個變量,即:

a, b = b, a

 

2、列表推導式

列表推導式是java及C++等語言沒有的特性,能夠很簡潔的實現for循環,可以應用列表,集合或者子字典。

例如我們要求20以內的整除3的數的平方的列表,可以用如下代碼實現:

numbers = []
for x in xrange(20):
    if x % 3 == 0:
        numbers.append(x*x)

而通過列表推導式一行代碼就可以實現:

numbers = [x*x for x in xrange(20) if x % 3 == 0]

列表推導式可以用於集合和字典,將[...] 變為[...]。集合和字典的實現如下所示:

集合:

numbers = {x*x for x in range(0, 20) if x % 3 == 0}

字典:

numbers = {x: x*x for x in range(0, 20) if x % 3 == 0}

 

3、字符串拼接

這是一個老生常談的問題,當我們需要將數個字符串拼接起來的時候,習慣性的使用 “+” 作為連接字符串的手段。

然而,由於像字符串這種不可變對象在內存中生成后無法修改,合並后的字符串會重新開辟一塊內存空間來存儲。因此沒合並一次就會單獨開辟一塊內存空間,這樣會占用大量的內存,嚴重影響代碼的效率.

words =['I', ' ', 'LOVE', ' ', 'pYTHON', '.']

sentence = ''
for word in words:
    sentence += '' + word

解決這個問題的辦法是使用字符串連接的join,Python寫法如下:

words = ['i', ' ', 'love', 'python','']

sentence = ''.join(words)

 

4.如何快速翻轉字符串

java 或者 C++ 等語言的寫法是新建一個字符串,從最后開始訪問員字符串:

a = 'I love python.'

reverse_a = ''
for i in range(0, len(a)):
    reverse_a += a[len(a) - i - 1]

而Python則將字符串看做list,而列表可以通過切片操作來實現翻轉:

a = "I LOVE PYTHON"

reverse_a = a[::-1]

 

5、for/else 語句

在C語言或java語言中,我們尋找一個字符串是否在一個list中,通常會設置一個布爾型變量表示是否找到:

cities = ['Beijing', 'Shanghai', 'Tianjin', 'Shenzhen','Wuhan']
tofind = 'Shanghai'

found = False
for city in cities:
    if tofind == city:
        print('Found')
        found = True
        break
if not found:
    print('Not found!')

 

而python中通過for ... else ... 會使得代碼很簡潔,注意else中的代碼快僅僅是在for循環中沒有執行break語句的時候執行:

cities = ['BeiJing', 'TianJin', 'JiNan', 'ShenZhen', 'WuHan']
tofind = 'Shanghai'

for city in citiees:
    if tofind == city:
        print('Found')
        break
else:
    print('Not found!')

 

另外,while和try關鍵字都可以和else搭配使用

6、迭代對象善用enumerate類

enumerate類接收兩個參數,其中一個是可以地迭代的對象,另外一個是開始的索引。比如,我們想要的打印一份列表的索引機器內容,可以用如下代碼實現:

cities = ['Beijing', 'Shanghai', 'Wuhan']

index = 0 
for city in cities:
    index = index + 1
    print(index, ':', 'city')

而通過使用enumerate則極大的簡化了代碼,這里索引設置為從1開始(默認是從 0 開始):

cities = ['Beijing', 'Shanghai', 'Wuhan']

for index, ciity in enumerate(cities, 1):
    print(index, ':', city)

 

7、通過lambda來定義函數

lambda可以返回一個可以調用的函數對象,會使得代碼更為簡潔,若不使用lambda則需要單獨定義一個函數:

def f(x):
    return x*x

map(f, [1,2,3,4,5,6,7,8])

使用lambda后僅僅使用一行代碼:

map(lambda x: x * x,[1,2,3,4,5,6,7,8] )

這里注意,lambda生成的是一個可以向其他函數一樣使用的函數對象,即

def f(x);
    return x *x

等價於

lambda x : x*x

8、應用上下文管理

 在打開文件時,通常是通過捕獲異常來進行實現的,並且在finally模塊中對文件來進行關閉:

try:
    file = open('python.txt')
    for line in file:
        print(line)
except:
    print('File error!')
finally:
    file.close()

而通過上下文管理中的with語句可以讓代碼非常簡潔:

with open('python.txt') as file:
    for line in file:
        print(line)

9、使用裝飾器

裝飾器在Python中的應用非常廣泛,其特點是可以再具體函數執行之前或者之后做相關的操作。比如:執行前打印執行函數的相關信息,對函數的參數進行校驗,執行后記錄函數調用的相關日志等,使用裝飾器可以用如下代碼實現:

from time import ctime

 def foo():
    print("[%s] %() is called" % (ctime(), foo.__name__))
    print('Hello , Python')

這樣寫的問題是業務邏輯中會夾雜參數檢查,日志記錄等信息,是得代碼邏輯不夠清晰,所以,這種場合需要使用裝飾器:

from time import ctime 

def deco(func):
    def decorator(*args,**kwargs):
        print("[%s] %s() is called" % (citme(), func,__name__)
        return  func(*args, **kwargs)
    return decorator


@deco
def foo():
    print("Hello Python")

 

10、使用生成器

生成器與列表最大的區別就是,列表是一次行生成的,需要較大的內存空間;而生成器是需要的時候生成的,基本不占用內存空間,生成器分為生成器表達式和生成器函數:

先看一下列表:

l = [x for x in range(10)]

改成生成器只需要將[ .. ]變為(...),即

g = (x  for x in range(10))

至於生成器函數,是通過yield關鍵字來實現的,我們一計算斐斐波那契數列為例,使用列表可以用如下代碼來說實現:

def fib(max):
     n, a, b = 0, 0, 1
    fibonacci = []
    while n < max:
        fibonacci,append(b)
        a, b = b, a + b
        n = n + 1
    return fibonacci

而使用生成器則變為:

def fib(max);
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a+b
        n = n + 1

11、counter的使用

通常的詞頻統計中,我們的思路是:

 需要一個字典,key值存儲單詞,value存儲對應的詞頻。當遇到一個單詞,判斷是否在這個字典中,如果是,則詞頻加1,如果否,則字典中新增這個單詞,同時對應的詞頻設置為1.

對應的Python代碼實現如下:

# 統計單詞出現的次數
def computeFrequencies(wordList):
    # 詞頻字典
    wordfrequencies = {}
    
    for word in wordList:
        if word not in wordfrequescies;
        #單詞不在單詞詞頻字典中,詞頻設置為1
            wordfrequescies[word] = 1
        else:
            # 單詞在單詞詞頻字典中,詞頻加   1
            wordfrequencies[word] += 1
    return wordfrequencies

有沒有更簡單的方法嗎?答案是肯定的,就是使用Counter。collection中的Counter類就完成了這樣的功能,他是字典類的一個子類。Python代碼變得無比簡潔:

# 統計單詞出現的頻次
def computeFrequencies(wordList):
    # 詞頻字典
    wordfrequencies = Counter(wordList)
    return wordfrequencies

 

12、鏈式比較

在實際的數字比較中,我們可能需要多次比較多次,比如我們判斷學習成績是否位與某個區間:

x = 79

>>> x < 80 and x > 70
True

變更Pythonic的寫法變身鏈式比較:即:

x  = 79

>>> 80 < x 90
False

>>> 70 < x < 80
True

這種寫法給人的感受也更為直觀易懂。

13、函數返回多個值

在java語言中,當函數需要返回多個值時,通常的做法是生成一個Response對象,然后將要返回的值寫入對象內部,而Python不需要這樣做。可以直接返回多個值:

def f();
    error_code = 0
    error_desc = "成功"
    return error_code, error_desc

使用的時候也會非常簡單:

code, desc = f()
print(code, desc)

14、使用*運算符

*運算符和 ** 運算符完美的解決了將元組參數、字典參數進行 unpack,從而簡化了函數定義的形式,如:

def fun(*args):
    for eacharg in args:
        print('tuple arg:', eacharg)

fun('I', 'LOVE', 'PYTHON')

運行的結果:

tuple arg: I

tuple arg: love

tuple arg: Python

 

15、找出列表中出現最多的數:

  這是經常遇到的一個問題。解決這個問題的其中一個思路是按照標題 11 提供的詞頻統計的方法,先統計詞頻,然后遍歷字典,找出具有最大詞頻的數字,有沒有簡潔的方式?

當然,Python代碼入下:

num = [1,2,3,4,4,4,4, 2,3,4,5,6,7,8,9]

ptint(max(set(num), key=num.count))

 


免責聲明!

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



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