geekdoc-python-zh/docs/pythonland/35.md

121 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Python 函数:高级概念
> 原文:[https://python.land/deep-dives/functions](https://python.land/deep-dives/functions)
您知道如何强制关键字参数、创建函数装饰器、创建匿名函数或者将数组或字典解包到函数的参数中吗?在这篇 Python 函数高级概念的文章中,我们将讨论一些围绕函数的更高级的概念。我将这些放在一篇单独的文章中,因为我不想让初学者对这些概念感到困惑。
你可能想先阅读我们对 Python 函数的[介绍。](https://python.land/introduction-to-python/functions)
目录
* [强制关键字参数](#Forced_keyword_arguments "Forced keyword arguments")
* [使用*和**作为函数参数](#Using_and_for_function_arguments "Using * and ** for function arguments")
* [装饰您的功能](#Decorating_your_functions "Decorating your functions")
* [匿名函数](#Anonymous_functions "Anonymous functions")
## 强制关键字参数
关键字参数有许多优点:
* 你没有被强迫按照特定的顺序来提供你的论点——名字很重要,而不是立场。
* 关键字参数提供了清晰度。不用查函数本身,你通常可以通过看名字猜出参数的用途。
那很好,但是你可能已经知道这些事情了。您可能不知道的是,您还可以强制关键字参数。在 PEP 3202 中描述了细节,但是归结起来就是在想要强制作为关键字参数的参数前使用星号。或者,如下所示,在所有参数之前,强制所有参数都是关键字参数:
```py
>>> def f(*, a, b):
... print(a, b)
...
>>> f(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional
arguments but 2 were given
>>> f(a=1, b=2)
1 2
>>>
```
当您开发某种类型的库时,这个高级函数技巧可能会派上用场。也许你还不想坚持某个论点的顺序。在这种情况下,这是强制库的用户使用命名参数的方法,使顺序变得无关紧要。
## 使用*和**作为函数参数
有些函数需要很长的参数列表。虽然这应该完全避免,例如,通过使用[数据类](https://python.land/python-data-classes),但这并不总是由你决定。在这种情况下,第二个最好的选择是创建一个包含所有命名参数的[字典](https://python.land/python-data-types/dictionaries),并将其传递给函数。这通常会使您的代码更具可读性。您可以通过使用前缀`**`来解包字典,以便与命名的关键字一起使用:
```py
>>> def f(a, b):
... print(a, b)
...
>>> args = { "a": 1, "b": 2 }
>>> f(**args)
1 2
```
类似地,我们可以使用单个`*`来解包一个列表,并将其内容作为位置参数提供给一个函数:
```py
>>> def f(a, b, c):
... print(a, b, c)
...
>>> l = [1, 2, 3]
>>> f(*l)
1 2 3
```
## 装饰您的功能
装饰器是一个函数的包装器它以某种方式修改函数的行为。decorators 有许多用例,您可能以前在使用 Flask 这样的框架时使用过。
让我们创建自己的装饰器;它比你想象的要简单,也许有一天会派上用场:
```py
def print_argument(func):
def wrapper(the_number):
print("Argument for", func.__name__, "is", the_number)
return func(the_number)
return wrapper
@print_argument
def add_one(x):
return x + 1
print(add_one(1))
```
在`print_argument`中,我们定义了一个包装函数。该函数打印被调用函数的参数和名称。接下来,它执行实际的函数并返回结果,就像函数被定期调用一样。使用`@print_argument`,我们将装饰器应用于一个函数。也许没有必要说:这个装饰器也可以在其他函数中重用。
我们的小脚本的输出将是:
```py
Argument for add_one is 1
2
```
## 匿名函数
有时候命名一个函数是不值得的。一个例子是当你确定函数只会被使用一次。对于这种情况Python 为我们提供了匿名函数,也称为 lambda 函数。
lambda 函数可以赋给一个变量,从而创建了一种简洁的函数定义方式:
```py
>>> add_one = lambda x: x + 1
>>> add_one(3)
4
```
当你需要使用一个函数作为参数时,这就变得更有趣了。在这种情况下,该函数通常只使用一次。如您所知,`map`将一个函数应用于一个可迭代对象的所有元素。我们可以在调用 map 时使用 lambda:
```py
>>> numbers = [1, 2, 3, 4]
>>> times_two = map(lambda x: x * 2, numbers)
>>> list(times_two)
[2, 4, 6, 8]
>>>
```
事实上,这是一种你会经常看到的模式。当你需要对一个 iterable 对象的每个元素应用一个相对简单的操作时,结合 lambda 函数使用`map()`既简洁又高效。