Supporting Python 3(支持python3)——使用現代的風格改善你的代碼

使用現代風格改善你的代碼

原文: http://python3porting.com/improving.htmlhtml

譯者: TheLover_Zpython

一旦你開始使用 Python 3,你就有機會接觸新的特性來改善你的代碼。這篇文章中提到的不少東西實際上在 Python 3 以前就已經被支持了。但我仍是要提一下它們,由於知道了這些之後你的代碼能夠從中獲益。我說的包括修飾器,在 Python 2.2 開始提供支持; sorted() 方法,在 Python 2.4 開始提供支持;還有上下文管理,在 Python 2.5 開始提供支持。併發

這裏說起的其它新特性在 Python 2.6 或者 2.7 都提供了支持,因此說若是你不是在用 Python 2.5 和以前的版本的話,你可使用這裏提到的幾乎所有的新特性。app

使用 sorted() 來替代 .sort()

在 Python 中,列表有一個 .sort() 方法能夠進行排序。 .sort() 會影響列表的結構。下面這麼寫是由於在 Python 2.3 以前只能這麼寫。函數

>>> infile = open('pythons.txt')
>>> pythons = infile.readlines()
>>> pythons.sort()
>>> [x.strip() for x in pythons]
['Eric', 'Graham', 'John', 'Michael', 'Terry', 'Terry']

Python 2.4 開始加入了新的支持 sorted() ,它會返回一個排好序的列表而且接受和 .sort() 同樣的參數。使用 sorted() 你能夠避免改變列表的結構。它還能夠接受迭代器做爲輸入而不僅是列表,這樣可讓你的代碼看起來更棒。編碼

>>> infile = open('pythons.txt')
>>> [x.strip() for x in sorted(infile)]
['Eric', 'Graham', 'John', 'Michael', 'Terry', 'Terry']

然而,若是你把 mylist.sort() 替換爲 mylist = sorted(mylist) 是沒有用的,並且還會消耗更多的內存。url

2to3 有時會把 .sort() 改成 sorted()spa

使用上下文管理器來編寫代碼

從 Python 2.5 開始你可使用上下文管理器,它容許你創造和管理運行時內容。若是你以爲聽起來有點兒抽象,那就對了。上下文管理器確實很抽象而且很靈活,很容易被誤用,我這就教你怎麼正確運用它。.net

上下文管理器被用來看成 with 的一部分,在 with 的代碼塊內都有效。在代碼塊結束的時候上下文管理器退出。這可能聽起來不是那麼使人激動,除非我告訴你你可使用它來實現資源分配。你進入上下文的時候資源管理器分配資源,你退出的時候它釋放資源。code

最經常使用的例子是讀寫文件。在大多數的更面向底層的語言中你必須記得關閉已打開的文件,但在 Python 中你不須要這麼作。然而有時候你必須確認你關掉了文件,好比說你在循環中打開了許多文件以致於你用完了文件名。

>>> f = open('/tmp/afile.txt', 'w')
>>> try:
...     n = f.write('sometext')
... finally:
...     f.close()

你也能夠這麼寫,使用上下文管理器。

>>> with open('/tmp/afile.txt', 'w') as f:
...     n = f.write('sometext')

當你使用上下文管理器的時候,代碼塊結束的時候文件就會自動關閉,就算是有錯誤發生也是這樣。正如你所看到的那樣,代碼量少了不少,可是更重要的是程序看起來乾淨多了,也易讀了。

另外一個例子是若是你想要重定向標準輸出。正如前面同樣,你會使用 try/except 。那樣也不錯,若是你只使用一次的話。可是若是你有不少次這樣的需求的話,上下文管理器是你不二的選擇。

>>> import sys
>>> from StringIO import StringIO
>>> class redirect_stdout:
...     def __init__(self, target):
...         self.stdout = sys.stdout
...         self.target = target
...
...     def __enter__(self):
...         sys.stdout = self.target
...
...     def __exit__(self, type, value, tb):
...         sys.stdout = self.stdout
...
>>> out = StringIO()
>>> with redirect_stdout(out):
...     print 'Test'
...
>>> out.getvalue() == 'Test\n'
True

碰到 with 語句之後 __enter__ 方法被調用,退出的時候 __exit__() 被調用,包括引起錯誤。

上下文管理器在不少地方均可以使用。你的任何使用例外的代碼最好確保資源或者全局變量沒有被分配或者設置。

contextlib 庫有各類各樣的函數幫助你使用上下文管理器。好比說,若是你有一個有 .close() 方法但不是上下文管理器的對象,你可使用 closing() 函數來在 with 塊結束的時候自動關閉它們。

>>> from contextlib import closing
>>> import urllib
>>>
>>> book_url = ' 
>>> with closing(urllib.urlopen(book_url)) as page:
...     print len(page.readlines())
117

高級字符串格式化

在 Python 3 和 2.6 中,一種新的字符串格式支持被引進了。它更靈活而且有更聰明的語法。

舊的字符串格式:

>>> 'I %s Python %i' % ('like', 2)
'I like Python 2'

新的字符串格式:

>>> 'I {0} Python {1}'.format('♥', 3)'
I ♥ Python 3'

使用這些新特性你能夠實現一些比較瘋狂的小東西,可是玩過火的話你舊失去了它易讀的優勢:

>>> import sys
>>> 'Python {0.version_info[0]:!<9.1%}'.format(sys)
'Python 300.0%!!!'

更詳細的文檔請參考 Common String Operations

舊的字符串格式基於 % 的這個特性可能最終會被移除,不過最終日期尚未定。

類修飾器

修飾器在 Python 2.4 的時候被支持,而後有了內置的修飾器好比說 @property@classmethod ,修飾器開始變的流行。Python 2.6 引入了類修飾器。

類修飾器能夠用來包裹類或者修飾類。一個例子就是 functools.total_ordering ,可讓你實現最小的富比較操做符,而後增長到你的類。它們能夠做爲元類,類修飾器的例子就是修飾器能夠把類變成一個單獨的類。 zope.interface 類修飾器能夠註冊一個做爲特定接口的類。

集合

Python 3 中引入了一種新的集合語法。相對於 set([1, 2, 3]) 你可使用更乾淨語法的 {1, 2, 3} 。兩種語法在 Python 3 中均可以工做,可是更建議使用新的語法。

>>> set([1,2,3]){1, 2, 3}

yield 和 生成器

就像浮點除法操做符和 .sort()key 參數,生成器已經在不知不覺深刻了咱們的編碼生活。雖然很少見,但它們仍是很是實用的,能夠幫你節省內存,簡化代碼。咱們來看看這個例子:

>>> def allcombinations(starters, endings):
...    result = []
...    for s in starters:
...         for e in endings:
...             result.append(s+e)
...     return result

這麼寫就優雅多了:

>>> def allcombinations(starters, endings):
...     for s in starters:
...         for e in endings:
...             yield s+e

生成器在 Python 2.2 開始加入支持,可是 Python 2.4 進行了一些改進。看起來很像是列表表達式,但並不返回列表而是返回表達式。它們在有列表表達式的地方几乎均可以使用。

>>> sum([x*x for x in xrange(2000000)])
2666664666667000000L

能夠寫做:

>>> sum(x*x for x in xrange(2000000))
2666664666667000000L

更多的推導式

在 Python 3 和 2.6 中,生成器推導式被引進。它就是簡單的一個帶括號的生成器表達式,能夠和列表推導式同樣工做,返回一個生成器而不是列表。

>>> (x for x in 'Silly Walk')
<generator object <genexpr> at ...>

在 Python 3 中生成器推導式不只僅是一個新的漂亮的特性,而是一個重要的改變,由於生成器推導式如今是其它全部內置推導式的基礎。在 Python 3 中列表推導式只是一個給 list 類型的構造器提供生成器表達式的語法糖。

>>> list(x for x in 'Silly Walk')
['S', 'i', 'l', 'l', 'y', ' ', 'W', 'a', 'l', 'k']
>>> [x for x in 'Silly Walk']
['S', 'i', 'l', 'l', 'y', ' ', 'W', 'a', 'l', 'k']

這也意味着循環變量不再會摻入附近的命名空間了。

生成器推導式也能夠用 Python 2.6 及其之後版本的 dict()set() 構造器生成。可是在 Python 3 還有 Python 2.7 中,你能夠用新的語法來定義字典和列表推導式:

>>> department = 'Silly Walk'
>>> {x: department.count(x) for x in department}
{'a': 1, ' ': 1, 'i': 1, 'k': 1, 'l': 3, 'S': 1, 'W': 1, 'y': 1}
>>> {x for x in department}
{'a', ' ', 'i', 'k', 'l', 'S', 'W', 'y'}

新的模塊

還有許多新的模塊值得你一看。在這裏我就很少說了,由於大多數若是你不重寫軟件的話可能獲益很少,但你應該知道它們存在。你能夠翻看一下 Python 文檔來了解一下。

abc

abc 模塊包含了對生成抽象的基礎類的支持,你能夠 標記 一個基礎類的方法或者屬性爲「抽象」,意思是你必須在子類中進行實現,不然沒法實例化。

抽象基礎類也能夠建立沒有實體方法的類,用於定義接口。

abc 模塊在 Python 2.6 及其之後的版本被支持。

multiprocessingfuture

multiprocessing 是一個新的模塊,用於進行多進程操做,它容許你擁有進程隊列和使用鎖,還有用於同步進程的 信號標

multiprocessing 在 Python 2.6 之後被加入支持。在 2.4 和 2.5 你可使用 CheeseShop

若是你要作併發你能夠看一下 future 模塊,在 Python 3.2 引入了這個模塊,在 Python 2.5 及之後的版本能夠用 參考這裏

numbersfractions

Python 3 加入了這個庫。大多數狀況下你不會注意到它,可是頗有趣的是 fractions 模塊,在 Python 2.6 被支持。

>>> from fractions import Fraction
>>> Fraction(3,4) / Fraction('2/3')
Fraction(9, 8)

還有 numbers 模塊,包含支持全部數字類型的抽象基礎類。若是你正在實現你本身的數字類型的話,那麼它很是有用。

中英文對照

生成器推導式 - generator comprehension

列表推導式 - list comprehension

生成器 - generator

抽象的基礎類 - abstract base classes


在湖聞樟注:

引導頁Supporting Python 3:(支持Python3):深刻指南

目錄Supporting Python 3(支持Python 3)——目錄

相關文章
相關標籤/搜索