【Python】使用31条规则编写高质量且美丽的Python代码
Raymond Hettinger在pycon US 2013?視頻,幻燈片上的講話。
代碼示例和直接引用都來自Raymond的演講。我在這里復制它們是為了我自己的啟發和希望別人會發現它們像我一樣方便!
原文:https://github.com/JeffPaine/beautiful_idiomatic_python
?
基礎
1、循環一系列數字
for i in [0, 1, 2, 3, 4, 5]:print i**2for i in range(6):print i**2更好
for i in xrange(6):print i**2xrange在范圍內創建一個迭代器,一次生成一個值。這種方法比內存效率更高range。在python 3中xrange重命名為range。
?
2、循環收集
colors = ['red', 'green', 'blue', 'yellow']for i in range(len(colors)):print colors[i]更好
for color in colors:print color?
3、向后循環
colors = ['red', 'green', 'blue', 'yellow']for i in range(len(colors)-1, -1, -1):print colors[i]更好
for color in reversed(colors):print color?
4、循環收集和索引
colors = ['red', 'green', 'blue', 'yellow']for i in range(len(colors)):print i, '--->', colors[i]更好
for i, color in enumerate(colors):print i, '--->', color它快速而美觀,可以幫助您跟蹤各個索引并增加它們。
每當你發現自己在[集合]中操縱索引時,你可能做錯了。
?
5、循環兩個集合
names = ['raymond', 'rachel', 'matthew' colors = ['red', 'green', 'blue', 'yellow']n = min(len(names), len(colors)) for i in range(n):print names[i], '--->', colors[i]for name, color in zip(names, colors):print name, '--->', color更好
for name, color in izip(names, colors):print name, '--->', colorzip在內存中創建一個新列表并占用更多內存。izip效率比zip。注意:在python 3?izip中重命名zip并提升為內置替換舊的zip。
?
6、按排序順序循環
colors = ['red', 'green', 'blue', 'yellow']# Forward sorted order for color in sorted(colors):print colors# Backwards sorted order for color in sorted(colors, reverse=True):print colors?
7、自定義排序順序
colors = ['red', 'green', 'blue', 'yellow']def compare_length(c1, c2):if len(c1) < len(c2): return -1if len(c1) > len(c2): return 1return 0print sorted(colors, cmp=compare_length)更好
print sorted(colors, key=len)原作很慢,寫起來很不愉快。此外,python 3中不再提供比較功能。
?
8、調用函數直到sentinel值
blocks = [] while True:block = f.read(32)if block == '':breakblocks.append(block)更好
blocks = [] for block in iter(partial(f.read, 32), ''):blocks.append(block)iter有兩個論點。第一個你一遍又一遍地打電話,第二個是哨兵價值。
?
9、區分循環中的多個退出點
def find(seq, target):found = Falsefor i, value in enumerate(seq):if value found = Truebreakif not found:return -1return i更好
def find(seq, target):for i, value in enumerate(seq):if value == target:breakelse:return -1return i每個for循環內部都是一個else。
?
10、循環字典鍵
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}for k in d:print kfor k in d.keys():if k.startswith('r'):del d[k]什么時候應該使用第二個而不是第一個?當你改變字典。
如果你在迭代它時改變某些東西,那么你就生活在一種罪惡的狀態中,并且應該發生在你身上的事情。
d.keys()制作所有密鑰的副本并將其存儲在列表中。然后你可以修改字典。注意:在python 3中迭代一個字典你必須顯式寫:list(d.keys())因為d.keys()返回一個“字典視圖”(一個可以在字典鍵上提供動態視圖的迭代)。見文檔。
?
11、循環字典鍵和值
# Not very fast, has to re-hash every key and do a lookup for k in d:print k, '--->', d[k]# Makes a big huge list for k, v in d.items():print k, '--->', v更好
for k, v in d.iteritems():print k, '--->', viteritems()更好,因為它返回一個迭代器。注意:在python 3中沒有iteritems(),items()行為接近于什么iteritems()。見文檔。
?
12、從對構造字典
names = ['raymond', 'rachel', 'matthew' colors = ['red', 'green', 'blue']d = dict(izip(names, colors)) # {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}對于python 3:?d = dict(zip(names, colors))
?
13、用字典統計
colors = ['red', 'green', 'red', 'blue', 'green', 'red']# Simple, basic way to count. A good start for beginners. d = {} for color in colors:if color not in d:d[color] = 0d[color] += 1# {'blue': 1, 'green': 2, 'red': 3}更好
d = {} for color in colors:d[color] = d.get(color, 0) + 1# Slightly more modern but has several caveats, better for advanced users # who understand the intricacies d = collections.defaultdict(int) for color in colors:d[color] += 1?
14、用詞典分組 - 第一部分和第二部分
names = ['raymond', 'rachel', 'matthew', 'roger','betty', 'melissa', 'judith', 'charlie']# In this example, we're grouping by name length d = {} for name in names:key = len(name)if key not in d:d[key] = []d[key].append(name)# {5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew', 'melissa', 'charlie']}d = {} for name in names:key = len(name)d.setdefault(key, []).append(name)更好
d = collections.defaultdict(list) for name in names:key = len(name)d[key].append(name)?
15、是一個字典popitem()原子?
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}whilekey, value = d.popitem()print key, '-->', valuepopitem?是原子的,所以你不必在它周圍放置鎖以在線程中使用它。
?
16、鏈接詞典
defaults = {'color': 'red', 'user': 'guest'} parser = argparse.ArgumentParser() parser.add_argument('-u', '--user') parser.add_argument('-c', '--color') namespace = parser.parse_args([]) command_line_args = {k:v for k, v in vars(namespace).items() if v}# The common approach below allows you to use defaults at first, then override them # with environment variables and then finally override them with command line arguments. # It copies data like crazy, unfortunately. d = d.update(os.environ) d.update(command_line_args)更好
d = ChainMap(command_line_args, os.environ, defaults)ChainMap?已經被引入python 3.快速而美麗。
?
提高清晰度
- 位置論證和指標很好
- 關鍵字和名稱更好
- 第一種方式是方便計算機
- 第二個對應于人類的思考方式
18、使用關鍵字參數澄清函數調用
twitter_search('@obama', False, 20, True)更好
twitter_search('@obama', retweets=False, numtweets=20, popular=True)略微(微秒)慢,但值得為代碼清晰度和開發人員節省時間。
?
19、使用命名元組澄清多個返回值
# Old testmod return value doctest.testmod() # (0, 4) # Is this good or bad? You don't know because it's not clear.更好
# New testmod return value, a namedTuple doctest.testmod() # TestResults(failed=0, attempted=4)namedTuple是元組的子類,因此它們仍像普通元組一樣工作,但更友好。
要創建一個namedTuple:
TestResults = namedTuple('TestResults', ['failed', 'attempted'])?
20、解包序列
p = 'Raymond', 'Hettinger', 0x30, 'python@example.com'# A common approach / habit from other languages fname = p[0] lname = p[1] age = p[2] email = p[3]更好
fname, lname, age, email = p第二種方法使用元組解包,更快,更易讀。
?
21、更新多個狀態變量
def fibonacci(n):x = 0y = 1for i in range(n):t =y = x +x = t更好
def fibonacci(nx, y = 0, 1for i in range(n):print xx, y = y, x + y第一種方法的問題
- x和y是狀態,狀態應該一次全部更新,或者在狀態不匹配的行和問題的常見來源之間更新
- 訂購事宜
- 它的水平太低了
第二種方法是更高級別,不會冒錯誤的訂單并且速度快。
?
22、同步狀態更新
tmp_x = x + dx * tmp_y = y + dy * t # NOTE: The "influence" function here is just an example function, what it does # is not important. The important part is how to manage updating multiple # variables at once. tmp_dx = influence(m, x, y, dx, dy, partial='x') tmp_dy = influence(m, x, y, dx, dy, partial='y') x = tmp_x y = tmp_y dx = tmp_dx dy = tmp_dy更好
# NOTE: The "influence" function here is just an example function, what it does # is not important. The important part is how to manage updating multiple # variables at once. x, y, dx, dy = (x + dx * t,y + dy * t,influence(m, x, y, dx, dy, partial='x'),influence(m, x, y, dx, dy, partial='y'))?
效率
- 優化基本規則
- 不要讓數據不必要地移動
- 只需要小心謹慎就可以避免O(n ** 2)行為而不是線性行為
基本上,只是不要不必要地移動數據。
23、連接字符串
names = ['raymond', 'rachel', 'matthew', 'roger','betty', 'melissa', 'judith', 'charlie']s = names[0] for name in names[1:]:s += ', ' + name print s更好
print ', '.join(names)?
24、更新序列
names = ['raymond', 'rachel', 'matthew', 'roger','betty', 'melissa', 'judith', 'charlie']del names[0] # The below are signs you're using the wrong data structure names.pop(0) names.insert(0, 'mark')更好
names = collections.deque(['raymond', 'rachel', 'matthew', 'roger','betty', 'melissa', 'judith', 'charlie'])# More efficient with collections.deque del names[0] names.popleft() names.appendleft('mark')?
裝飾器和上下文管理器
- 幫助將業務邏輯與管理邏輯分開
- 用于分解代碼和改進代碼重用的干凈,漂亮的工具
- 良好的命名至關重要。
- 記住蜘蛛俠規則:強大的力量,責任重大!
?
25、使用裝飾器來分解管理邏輯
# Mixes business / administrative logic and is not reusable def web_lookup(url, saved={}):if url in saved:return saved[url]page = urllib.urlopen(url).read()saved[url] = pagereturn page更好
@cache def web_lookup(url):return urllib.urlopen(url).read()注意:因為python 3.2在標準庫中有一個裝飾器:functools.lru_cache。
?
26、因子分解臨時背景
# Saving the old, restoring the new old_context = getcontext().copy() getcontext().prec = 50 print Decimal(355) / Decimal(113) setcontext(old_context)更好
?
27、如何打開和關閉文件
f = open('data.txt') try:data = f.read() finally:f.close()更好
with open('data.txt') as f:data = f.read()?
28、如何使用鎖
# Make a lock lock = threading.Lock()# Old-way to use a lock lock.acquire() try:print 'Critical section 1'print 'Critical section 2' finally:lock.release()更好
# New-way to use a lock with lock:print 'Critical section 1'print 'Critical section 2'?
29、因子分解臨時背景
try:os.remove('somefile.tmp') except OSError:pass更好
with ignored(OSError):os.remove('somefile.tmp')ignored是python 3.4中的新功能,文檔。注意:ignored實際上是suppress在標準庫中調用的。
ignored在此期間制作自己的上下文管理器:
@contextmanager def ignored(*exceptions):try:yieldexcept exceptions:pass堅持在您的utils目錄中,你也可以忽略異常
?
30、因子分解臨時背景
# Temporarily redirect standard out to a file and then return it to normal with open('help.txt', 'w') as f:oldstdout = sys.stdoutsys.stdout = ftry:help(pow)finally:sys.stdout = oldstdout更好
with open('help.txt', 'w') as f:with redirect_stdout(f):help(pow)redirect_stdout建議用于python 3.4,bug報告。
滾動自己的redirect_stdout上下文管理器
@contextmanager def redirect_stdout(fileobj):oldstdout = sys.stdoutsys.stdout = fileobjtry:yield fileobjfinallysys.stdout = oldstdout?
簡潔富有表現力的單行
兩條相互矛盾的規則:
- 不要在一條線上放太多
- 不要將思想原子分解為亞原子粒子
雷蒙德的規則:
- 一行邏輯代碼等于英語中的一個句子
31、列表理解和生成器表達式
result = [] for i in range(10):s = i ** 2result.append(s) print sum(result)更好
print sum(i**2 for i in xrange(10))第一種方式告訴你該做什么,第二種方式告訴你你想要什么。
總結
以上是生活随笔為你收集整理的【Python】使用31条规则编写高质量且美丽的Python代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [组图]国外专家谈游戏制作
- 下一篇: Android Binder 之 Ser