3 個到今天仍然有用的 Python 3.2 特性
探索一些未被充分利用但仍然有用的 Python 特性。
這是Python 3.x 首發(fā)特性系列文章中的第三篇。其中一些 Python 版本已經(jīng)推出了一段時間。例如,Python 3.2 是在 2011 年首次發(fā)布的,但其中引入的一些很酷、很有用的特性仍然沒有被使用。下面是其中的三個。
argparse 子命令
argparse
模塊首次出現(xiàn)在 Python 3.2 中。有許多用于命令行解析的第三方模塊。但是內(nèi)置的 argparse
模塊比許多人認(rèn)為的要強大。
要記錄所有的 argparse
的特性,那需要專門寫系列文章。下面是一個例子,說明如何用 argparse
做子命令。
想象一下,一個命令有兩個子命令:negate
,需要一個參數(shù),multiply
,需要兩個參數(shù):
$ computebot negate 5
-5
$ computebot multiply 2 3
6
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
add_subparsers()
方法創(chuàng)建一個對象,你可以向其添加子命令。唯一需要記住的技巧是,你需要添加通過 set_defaults()
調(diào)用的子命令:
negate = subparsers.add_parser("negate")
negate.set_defaults(subcommand="negate")
negate.add_argument("number", type=float)
multiply = subparsers.add_parser("multiply")
multiply.set_defaults(subcommand="multiply")
multiply.add_argument("number1", type=float)
multiply.add_argument("number2", type=float)
我最喜歡的一個 argparse
功能是,因為它把解析和運行分開,測試解析邏輯特別令人愉快。
parser.parse_args(["negate", "5"])
Namespace(number=5.0, subcommand='negate')
parser.parse_args(["multiply", "2", "3"])
Namespace(number1=2.0, number2=3.0, subcommand='multiply')
contextlib.contextmanager
上下文是 Python 中一個強大的工具。雖然很多人 使用 它們,但編寫一個新的上下文常常看起來像一門黑暗藝術(shù)。有了 contextmanager
裝飾器,你所需要的只是一個一次性的生成器。
編寫一個打印出做某事所需時間的上下文,就像這樣簡單:
import contextlib, timeit
@contextlib.contextmanager
def timer():
before = timeit.default_timer()
try:
yield
finally:
after = timeit.default_timer()
print("took", after - before)
你可以這樣使用:
import time
with timer():
time.sleep(10.5)
took 10.511025413870811`
functools.lru_cache
有時,在內(nèi)存中緩存一個函數(shù)的結(jié)果是有意義的。例如,想象一下經(jīng)典的問題:“有多少種方法可以用 25 美分、1 美分、2 美分和 3 美分可以來換取 1 美元?”
這個問題的代碼可以說是非常簡單:
def change_for_a_dollar():
def change_for(amount, coins):
if amount == 0:
return 1
if amount < 0 or len(coins) == 0:
return 0
some_coin = next(iter(coins))
return (
change_for(amount, coins - set([some_coin]))
+
change_for(amount - some_coin, coins)
)
return change_for(100, frozenset([25, 10, 5, 1]))
在我的電腦上,這需要 13ms 左右:
with timer():
change_for_a_dollar()
took 0.013737603090703487`
事實證明,當(dāng)你計算有多少種方法可以做一些事情,比如用 50 美分找錢,你會重復(fù)使用相同的硬幣。你可以使用 lru_cache
來避免重復(fù)計算。
import functools
def change_for_a_dollar():
@functools.lru_cache
def change_for(amount, coins):
if amount == 0:
return 1
if amount < 0 or len(coins) == 0:
return 0
some_coin = next(iter(coins))
return (
change_for(amount, coins - set([some_coin]))
+
change_for(amount - some_coin, coins)
)
return change_for(100, frozenset([25, 10, 5, 1]))
with timer():
change_for_a_dollar()
took 0.004180959425866604`
一行的代價是三倍的改進(jìn)。不錯。
歡迎來到 2011 年
盡管 Python 3.2 是在 10 年前發(fā)布的,但它的許多特性仍然很酷,而且沒有得到充分利用。如果你還沒使用,那么將他們添加到你的工具箱中。