这是关于 Python 3.x 版本中首次出现的功能系列的第三篇文章。其中一些 Python 版本已经发布一段时间了。 例如,Python 3.2 于 2011 年首次发布,但其中一些很酷且有用的功能仍然未被充分利用。 这里有三个。
argparse 子命令
argparse
模块首次出现在 Python 3.2 中。 有许多用于命令行解析的第三方模块。 但是内置的 argparse
模块比许多人认为的要强大得多。
记录 argparse
的所有来龙去脉将需要自己的系列文章。 为了让您尝鲜,这里有一个示例,说明如何使用 argparse
执行子命令。
想象一个带有两个子命令的命令:negate
,它接受一个参数,以及 multiply
,它接受两个参数
$ computebot negate 5
-5
$ computebot multiply 2 3
6
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
add_subparsers()
方法创建一个可以向其中添加子命令的对象。 唯一需要记住的技巧是,您需要通过 set_defaults()
添加调用的子命令
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 中的一个强大工具。 虽然许多人使用它们,但编写新的上下文通常看起来像是一门黑暗艺术。 使用 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
有时,将函数的结果缓存在内存中是有意义的。 例如,想象一下经典问题:“使用四分之一美元、一角硬币、五分镍币和美分,有多少种方法可以兑换一美元?”
此代码可能出奇地简单
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]))
在我的电脑上,这大约需要 13 毫秒
with timer():
change_for_a_dollar()
took 0.013737603090703487
事实证明,当您计算出有多少种方法可以做类似用 50 美分兑换零钱的事情时,您会重复使用相同的硬币。 您可以使用 lru_cache
来避免一遍又一遍地重新计算。
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
一行代码的成本带来了三倍的改进。 还不错。
欢迎来到 2011 年
尽管 Python 3.2 是 10 年前发布的,但它的许多功能仍然很酷且未被充分利用。 如果您还没有这样做,请将它们添加到您的工具包中。
评论已关闭。