1. 程式人生 > >Python心得--如何提高代碼質量

Python心得--如何提高代碼質量

python 代碼質量 pythonic

前些日子用python基於prometheus開發了一個vsphere volume卷監控的exporter,於是跟vsphere的api(pyvmomi)接口打上了交道,開發的過程中你會發現pyvmomi的接口返回的對象好多列表類型的,當你取其中一個對象的時候可能需要進行多層的循環遍歷。於是促使了我寫這一篇文章,記錄一下在使用python搬磚過程中的一些心得體會。如有錯誤,歡迎大家指正。

技術分享

Python裏面所謂高質量的代碼,我自己理解的主要是兩方面。一是編寫具有python風格的代碼,即所謂的Pythonic;二是代碼的執行效率。Python的執行效率一直被人詬病,這點我承認,但我更認同的一種說法是“編程語言本身沒有好壞,關鍵在於使用者的使用方法是否恰當。”

以下是個人總結的,在python編程過程中常見的幾點提高代碼質量的方法:

  1. 變量的賦值

In [11]: a, b = 10, 50 # 賦值寫在一行
In [12]: a
Out[12]: 10
In [13]: b
Out[13]: 50
In [14]: a, b = b, a # a, b互換
In [15]: a
Out[15]: 50
In [16]: b
Out[16]: 10

變量交換的時候盡量避免使用中間變量增加開銷。

2. 列表推導提高效率和可讀性

如下生成一個新的列表:

In [17]: [n for n in range(10)]
Out[17]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

另一方面,列表推導也可能被濫用。通常的原則是,只用列表推導來創建新的列表並且盡量保持簡短。 如果列表推導的代碼超過了兩行,你可能就要考慮是不是得用 for 循環重寫了。就跟寫文章一樣,並沒有什麽硬性的規則,這個度需要自己把握。

3. 列表和字典的叠代

列表使用enumerate() 獲取list的索引和值,字典使用iteritems方法獲取索引和值。

In [18]: l1 = [n for n in range(10)]
In [21]: for k, v in enumerate(l1):
....: print k, v
....:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
In [23]: dict1 = {‘a‘:1, ‘b‘:2, ‘c‘:3, ‘d‘:4}
In [24]: dict1
Out[24]: {‘a‘: 1, ‘b‘: 2, ‘c‘: 3, ‘d‘: 4}
In [25]: for k, v in dict1.iteritems():
....: print k, v
....:
a 1
c 3
b 2
d 4

4. 使用三元表達式進行條件賦值

三元表達式允許用簡單的一行快速判斷,而不是使用復雜的多行if語句,可以使代碼簡單、可維護。

In [26]: 1 if 5>3 else 0
Out[26]: 1
In [27]: 1 if 5>8 else 0
Out[27]: 0

舉一個在實際生產中運用列表推導和三元表達式結合使用的例子:

dc_list = [datacenter for datacenter in root_folder.childEntity if isinstance(
datacenter, vim.Datacenter)]

這裏生成了一個名為dc_list的列表,首先在"root_folder.childEntity"中遍歷出datacenter,接著判斷這個datacenter是否是一個"vim.Datacenter"的實例,如果為真,加入到dc_list列表中,最終返回該datacenter列表。

5. 使用 with 自動關閉資源

對文件操作完成後應該立即關閉它們,因為打開的文件不僅會占用系統資源,而且可能影響其他程序或者進程的操作,甚至會導致用戶期望與實際操作結果不一致。

In [5]: with open(‘111.py‘, ‘rb‘) as file:
...: for line in file:
...: print line
...:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
print "name is %s" % __file__

6. 使用yield

這裏有一個生成斐波那契數列的例子:

In [8]: def fab(n):
...: a, b = 0, 1
...: for i in xrange(n):
...: yield b
...: a, b = b, a + b
...:
In [9]: fab(20)
Out[9]: <generator object fab at 0x1092975a0>
In [10]: for n in fab(20):
....: print n
....:
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765

可以看出一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用 next()(在 for 循環中會自動調用 next())才開始執行。雖然執行流程仍按函數的流程執行,但每執行到一個 yield 語句就會中斷,並返回一個叠代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函數在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的叠代值。

7. 減少循環內部執行的計算

優化python循環的關鍵一點,是要減少Python在循環內部執行的工作量。

In [30]: a = range(10000)
In [31]: size_a = len(a)
In [32]: %timeit -n 1000 for i in a: k = len(a)
1000 loops, best of 3: 658 μs per loop
In [33]: %timeit -n 1000 for i in a: k = size_a
1000 loops, best of 3: 304 μs per loop

8. 字符串連接優先使用"join",而不是“+”

In [42]: letter = [‘a‘, ‘b‘, ‘c‘, ‘d‘]
In [43]: print ‘‘.join(letter)
abcd

9. None類型判斷

不要使用‘==’ None的形式:

if foo == None:
do_something()

正確用法:

if not foo:
do_something()

技術分享

10. “過早的優化是萬惡之源”

最後不得不提一下這句話,借用一下別人的詮釋:

Make it Work.
Make it Right.
Make it Fast.
不要跳過前面兩個直奔第三個!

本文出自 “xujpxm” 博客,請務必保留此出處http://xujpxm.blog.51cto.com/8614409/1971832

Python心得--如何提高代碼質量