[#]: subject: (3 Python 3.2 features that are still relevant today) [#]: via: (https://opensource.com/article/21/5/python-32) [#]: author: (Moshe Zadka https://opensource.com/users/moshez) [#]: collector: (lujun9972) [#]: translator: (geekpi) [#]: reviewer: ( ) [#]: publisher: ( ) [#]: url: ( ) 3 Python 3.2 features that are still relevant today ====== Explore some of the underutilized but still useful Python features. ![Business woman on laptop sitting in front of window][1] This the third article in a series about features that first appeared in a version of Python 3.x. Some of those Python versions have been out for a while. For example, Python 3.2 was first released in 2011, yet some of the cool and useful features introduced in it are still underused. Here are three of them. ### argparse subcommands The `argparse` module first appeared in Python 3.2. There are many third-party modules for command-line parsing. But the built-in `argparse` module is more powerful than many give it credit for. Documenting all the ins and outs of `argparse` would take its own article series. For a small taste, here is an example of how you can do subcommands with `argparse`. Imagine a command with two subcommands: `negate`, which takes one argument, and `multiply` which takes two: ``` $ computebot negate 5 -5 $ computebot multiply 2 3 6 [/code] [code] import argparse parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() ``` The `add_subparsers()` methods creates an object that you can add subcommands to. The only trick to remember is that you need to add what subcommand was called through a `set_defaults()`: ``` negate  = subparsers.add_parser("negate") negate.set_defaults(subcommand="negate") negate.add_argument("number", type=float) [/code] [code] multiply  = subparsers.add_parser("multiply") multiply.set_defaults(subcommand="multiply") multiply.add_argument("number1", type=float) multiply.add_argument("number2", type=float) ``` One of my favorite `argparse` features is that, because it separates parsing from running, testing the parsing logic is particularly pleasant. ``` `parser.parse_args(["negate", "5"])`[/code] [code]`    Namespace(number=5.0, subcommand='negate')`[/code] [code]`parser.parse_args(["multiply", "2", "3"])`[/code] [code]`    Namespace(number1=2.0, number2=3.0, subcommand='multiply')` ``` ### contextlib.contextmanager Contexts are a powerful tool in Python. While many _use_ them, writing a new context often seems like a dark art. With the `contextmanager` decorator, all you need is a one-shot generator. Writing a context that prints out the time it took to do something is as simple as: ``` import contextlib, timeit @contextlib.contextmanager def timer():     before = timeit.default_timer()     try:         yield     finally:         after = timeit.default_timer()         print("took", after - before) ``` And you can use it with just: ``` import time with timer():     time.sleep(10.5) [/code] [code]`    took 10.511025413870811` ``` ### functools.lru_cache Sometimes the caching results from a function in memory make sense. For example, imagine the classical problem: "How many ways can you make change for a dollar with quarters, dimes, nickels, and cents?" The code for this can be deceptively simple: ``` 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])) ``` On my computer, this takes around 13ms: ``` with timer():     change_for_a_dollar() [/code] [code]`    took 0.013737603090703487` ``` It turns out that when you calculate how many ways you can do something like making change from 50 cents, you use the same coins repeatedly. You can use `lru_cache` to avoid recalculating this over and over. ``` 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])) [/code] [code] with timer():     change_for_a_dollar() [/code] [code]`    took 0.004180959425866604` ``` A three-fold improvement for the cost of one line. Not bad. ### Welcome to 2011 Although Python 3.2 was released 10 years ago, many of its features are still cool—and underused. Add them to your toolkit if you haven't already. -------------------------------------------------------------------------------- via: https://opensource.com/article/21/5/python-32 作者:[Moshe Zadka][a] 选题:[lujun9972][b] 译者:[译者ID](https://github.com/译者ID) 校对:[校对者ID](https://github.com/校对者ID) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 [a]: https://opensource.com/users/moshez [b]: https://github.com/lujun9972 [1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-concentration-focus-windows-office.png?itok=-8E2ihcF (Woman using laptop concentrating)