mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
727c3eca74
@ -1,205 +0,0 @@
|
||||
[#]: subject: (3 features that debuted in Python 3.0 you should use now)
|
||||
[#]: via: (https://opensource.com/article/21/5/python-30-features)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
3 features that debuted in Python 3.0 you should use now
|
||||
======
|
||||
Explore some of the underutilized but still useful Python features.
|
||||
![Hands on a keyboard with a Python book ][1]
|
||||
|
||||
This is the first in a series of articles about features that first appeared in a version of Python 3.x. Python 3.0 was first released in 2008, and even though it has been out for a while, many of the features it introduced are underused and pretty cool. Here are three you should know about.
|
||||
|
||||
### Keyword-only arguments
|
||||
|
||||
Python 3.0 first introduced the idea of **keyword-only** arguments. Before this, it was impossible to specify an API where some arguments could be passed in only via keywords. This is useful in functions with many arguments, some of which might be optional.
|
||||
|
||||
Consider a contrived example:
|
||||
|
||||
|
||||
```
|
||||
def show_arguments(base, extended=None, improved=None, augmented=None):
|
||||
print("base is", base)
|
||||
if extended is not None:
|
||||
print("extended is", extended)
|
||||
if improved is not None:
|
||||
print("improved is", improved)
|
||||
if augmented is not None:
|
||||
print("augmented is", augmented)
|
||||
```
|
||||
|
||||
When reading code that calls this function, it is sometimes hard to understand what is happening:
|
||||
|
||||
|
||||
```
|
||||
`show_arguments("hello", "extra")`[/code] [code]
|
||||
|
||||
base is hello
|
||||
extended is extra
|
||||
|
||||
[/code] [code]`show_arguments("hello", None, "extra")`[/code] [code]
|
||||
|
||||
base is hello
|
||||
improved is extra
|
||||
```
|
||||
|
||||
While it is possible to call this function with keyword arguments, it is not obvious that this is the best way. Instead, you can mark these arguments as keyword-only:
|
||||
|
||||
|
||||
```
|
||||
def show_arguments(base, *, extended=None, improved=None, augmented=None):
|
||||
print("base is", base)
|
||||
if extended is not None:
|
||||
print("extended is", extended)
|
||||
if improved is not None:
|
||||
print("improved is", improved)
|
||||
if augmented is not None:
|
||||
print("augmented is", augmented)
|
||||
```
|
||||
|
||||
Now, you can't pass in the extra arguments with positional arguments:
|
||||
|
||||
|
||||
```
|
||||
`show_arguments("hello", "extra")`[/code] [code]
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
TypeError Traceback (most recent call last)
|
||||
|
||||
<ipython-input-7-6000400c4441> in <module>
|
||||
----> 1 show_arguments("hello", "extra")
|
||||
|
||||
|
||||
TypeError: show_arguments() takes 1 positional argument but 2 were given
|
||||
```
|
||||
|
||||
Valid calls to the function are much easier to predict:
|
||||
|
||||
|
||||
```
|
||||
`show_arguments("hello", improved="extra")`[/code] [code]
|
||||
|
||||
base is hello
|
||||
improved is extra
|
||||
```
|
||||
|
||||
### nonlocal
|
||||
|
||||
Sometimes, functional programming folks judge a language by how easy is it to write an accumulator. An accumulator is a function that, when called, returns the sum of all arguments sent to it so far.
|
||||
|
||||
The standard answer in Python before 3.0 was:
|
||||
|
||||
|
||||
```
|
||||
class _Accumulator:
|
||||
def __init__(self):
|
||||
self._so_far = 0
|
||||
def __call__(self, arg):
|
||||
self._so_far += arg
|
||||
return self._so_far
|
||||
|
||||
def make_accumulator():
|
||||
return _Accumulator()
|
||||
```
|
||||
|
||||
While admittedly somewhat verbose, this does work:
|
||||
|
||||
|
||||
```
|
||||
acc = make_accumulator()
|
||||
print("1", acc(1))
|
||||
print("5", acc(5))
|
||||
print("3", acc(3))
|
||||
```
|
||||
|
||||
The output for this would be:
|
||||
|
||||
|
||||
```
|
||||
1 1
|
||||
5 6
|
||||
3 9
|
||||
```
|
||||
|
||||
In Python 3.x, **nonlocal** can achieve the same behavior with significantly less code.
|
||||
|
||||
|
||||
```
|
||||
def make_accumulator():
|
||||
so_far = 0
|
||||
def accumulate(arg):
|
||||
nonlocal so_far
|
||||
so_far += arg
|
||||
return so_far
|
||||
return accumulate
|
||||
```
|
||||
|
||||
While accumulators are contrived examples, the ability to use the `nonlocal` keyword to have inner functions with state is a powerful tool.
|
||||
|
||||
### Extended destructuring
|
||||
|
||||
Imagine you have a CSV file where each row consists of several elements:
|
||||
|
||||
* The first element is a year
|
||||
* The second element is a month
|
||||
* The other elements are the total articles published that month, one entry for each day
|
||||
|
||||
|
||||
|
||||
Note that the last element is _total articles_, not _articles published per day_. For example, a row can begin with:
|
||||
|
||||
|
||||
```
|
||||
`2021,1,5,8,10`
|
||||
```
|
||||
|
||||
This means that in January 2021, five articles were published on the first day. On the second day, three more articles were published, bringing the total to 8. On the third day, two more articles were published.
|
||||
|
||||
Months can have 28, 30, or 31 days. How hard is it to extract the month, day, and total articles?
|
||||
|
||||
In versions of Python before 3.0, you might write something like:
|
||||
|
||||
|
||||
```
|
||||
`year, month, total = row[0], row[1], row[-1]`
|
||||
```
|
||||
|
||||
This is correct, but it obscures the format. With **extended destructuring**, the same can be expressed this way:
|
||||
|
||||
|
||||
```
|
||||
`year, month, *rest, total = row`
|
||||
```
|
||||
|
||||
This means that if the format ever changes to prefix a description, you can change the code to:
|
||||
|
||||
|
||||
```
|
||||
`_, year, month, *rest, total = row`
|
||||
```
|
||||
|
||||
Without needing to add `1` to each of the indices.
|
||||
|
||||
### What's next?
|
||||
|
||||
Python 3.0 and its later versions have been out for more than 12 years, but some of its features are underutilized. In the next article in this series, I'll look at three more of them.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/5/python-30-features
|
||||
|
||||
作者:[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/python-programming-code-keyboard.png?itok=fxiSpmnd (Hands on a keyboard with a Python book )
|
@ -0,0 +1,205 @@
|
||||
[#]: subject: (3 features that debuted in Python 3.0 you should use now)
|
||||
[#]: via: (https://opensource.com/article/21/5/python-30-features)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
你现在应该使用的在 Python 3.0 中首次亮相的 3 个特性
|
||||
======
|
||||
探索一些未被充分利用但仍然有用的 Python 特性。
|
||||
![Hands on a keyboard with a Python book ][1]
|
||||
|
||||
这是关于首次出现在 Python 3.x 版本中的特性的系列文章的第一篇。Python 3.0 于 2008 年首次发布,尽管它已经发布了一段时间,但它引入的许多特性都没有被充分利用,而且相当酷。这里有三个你应该知道的。
|
||||
|
||||
### 仅限关键字参数
|
||||
|
||||
Python 3.0 首次引入了**仅限关键字参数**参数的概念。在这之前,不可能指定一个 API,其中一些参数只能通过关键字传入。这在有许多参数,其中一些参数可能是可选的函数中很有用。
|
||||
|
||||
请看一个特意设计的例子:
|
||||
|
||||
|
||||
```
|
||||
def show_arguments(base, extended=None, improved=None, augmented=None):
|
||||
print("base is", base)
|
||||
if extended is not None:
|
||||
print("extended is", extended)
|
||||
if improved is not None:
|
||||
print("improved is", improved)
|
||||
if augmented is not None:
|
||||
print("augmented is", augmented)
|
||||
```
|
||||
|
||||
当阅读调用该函数的代码时,有时很难理解发生了什么:
|
||||
|
||||
|
||||
```
|
||||
`show_arguments("hello", "extra")`[/code] [code]
|
||||
|
||||
base is hello
|
||||
extended is extra
|
||||
|
||||
[/code] [code]`show_arguments("hello", None, "extra")`[/code] [code]
|
||||
|
||||
base is hello
|
||||
improved is extra
|
||||
```
|
||||
|
||||
虽然可以用关键字参数来调用这个函数,但这明显不是最好的方法。相反,你可以将这些参数标记为仅限关键字:
|
||||
|
||||
|
||||
```
|
||||
def show_arguments(base, *, extended=None, improved=None, augmented=None):
|
||||
print("base is", base)
|
||||
if extended is not None:
|
||||
print("extended is", extended)
|
||||
if improved is not None:
|
||||
print("improved is", improved)
|
||||
if augmented is not None:
|
||||
print("augmented is", augmented)
|
||||
```
|
||||
|
||||
现在,你不能用位置参数传入额外的参数:
|
||||
|
||||
|
||||
```
|
||||
`show_arguments("hello", "extra")`[/code] [code]
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
TypeError Traceback (most recent call last)
|
||||
|
||||
<ipython-input-7-6000400c4441> in <module>
|
||||
----> 1 show_arguments("hello", "extra")
|
||||
|
||||
|
||||
TypeError: show_arguments() takes 1 positional argument but 2 were given
|
||||
```
|
||||
|
||||
对该函数的有效调用更容易预测:
|
||||
|
||||
|
||||
```
|
||||
`show_arguments("hello", improved="extra")`[/code] [code]
|
||||
|
||||
base is hello
|
||||
improved is extra
|
||||
```
|
||||
|
||||
### nonlocal
|
||||
|
||||
有时,函数式编程的人根据编写累加器的容易程度来判断一种语言。 累加器是一个函数,当它被调用时,返回目前为止发给它的所有参数的总和。
|
||||
|
||||
在 3.0 之前,Python 的标准答案是:
|
||||
|
||||
|
||||
```
|
||||
class _Accumulator:
|
||||
def __init__(self):
|
||||
self._so_far = 0
|
||||
def __call__(self, arg):
|
||||
self._so_far += arg
|
||||
return self._so_far
|
||||
|
||||
def make_accumulator():
|
||||
return _Accumulator()
|
||||
```
|
||||
|
||||
虽然承认有些啰嗦,但这确实有效:
|
||||
|
||||
|
||||
```
|
||||
acc = make_accumulator()
|
||||
print("1", acc(1))
|
||||
print("5", acc(5))
|
||||
print("3", acc(3))
|
||||
```
|
||||
|
||||
这样做的输出结果将是:
|
||||
|
||||
|
||||
```
|
||||
1 1
|
||||
5 6
|
||||
3 9
|
||||
```
|
||||
|
||||
在Python 3.x中,**nonlocal** 可以用少得多的代码实现同样的行为。
|
||||
|
||||
|
||||
```
|
||||
def make_accumulator():
|
||||
so_far = 0
|
||||
def accumulate(arg):
|
||||
nonlocal so_far
|
||||
so_far += arg
|
||||
return so_far
|
||||
return accumulate
|
||||
```
|
||||
|
||||
虽然累加器是经过设计的例子,但使用 `nonlocal` 关键字来拥有具有状态的内部函数的能力是一个强大的工具。
|
||||
|
||||
### 扩展析构
|
||||
|
||||
想象一下,你有一个 CSV 文件,每一行由几个元素组成:
|
||||
|
||||
* 第一个元素是年份
|
||||
* 第二个元素是月
|
||||
* 其他元素是该月发表的全部文章,每天一个条目
|
||||
|
||||
|
||||
|
||||
请注意,最后一个元素是_文章总数_,而不是_每天发表的文章_。例如,一行的开头可以是:
|
||||
|
||||
|
||||
```
|
||||
`2021,1,5,8,10`
|
||||
```
|
||||
|
||||
这意味着在 2021 年 1 月,第一天发表了 5 篇文章。第二天,又多发表了三篇文章,使总数达到 8 篇。第三天,又多发表了两篇文章。
|
||||
|
||||
一个月可以有 28 天、30 天或 31 天。提取月份、日期和文章总数有多难?
|
||||
|
||||
在 3.0 之前的 Python 版本中,你可能会这样写:
|
||||
|
||||
|
||||
```
|
||||
`year, month, total = row[0], row[1], row[-1]`
|
||||
```
|
||||
|
||||
这是正确的,但它掩盖了格式。使用**扩展析构**,同样可以这样表达:
|
||||
|
||||
|
||||
```
|
||||
`year, month, *rest, total = row`
|
||||
```
|
||||
|
||||
这意味着如果格式加了前缀描述,你可以把代码改成:
|
||||
|
||||
|
||||
```
|
||||
`_, year, month, *rest, total = row`
|
||||
```
|
||||
|
||||
而不需要在每个索引中添加 `1`。
|
||||
|
||||
### 接下来是什么?
|
||||
|
||||
Python 3.0 和它的后期版本已经推出了 12 年多,但是它的一些功能还没有被充分利用。在本系列的下一篇文章中,我将会写另外三个。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/5/python-30-features
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者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/python-programming-code-keyboard.png?itok=fxiSpmnd (Hands on a keyboard with a Python book )
|
Loading…
Reference in New Issue
Block a user