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

4.7 KiB
Raw Permalink Blame History

Python 函数:高级概念

原文:https://python.land/deep-dives/functions

您知道如何强制关键字参数、创建函数装饰器、创建匿名函数或者将数组或字典解包到函数的参数中吗?在这篇 Python 函数高级概念的文章中,我们将讨论一些围绕函数的更高级的概念。我将这些放在一篇单独的文章中,因为我不想让初学者对这些概念感到困惑。

你可能想先阅读我们对 Python 函数的介绍。

目录

强制关键字参数

关键字参数有许多优点:

  • 你没有被强迫按照特定的顺序来提供你的论点——名字很重要,而不是立场。
  • 关键字参数提供了清晰度。不用查函数本身,你通常可以通过看名字猜出参数的用途。

那很好,但是你可能已经知道这些事情了。您可能不知道的是,您还可以强制关键字参数。在 PEP 3202 中描述了细节,但是归结起来就是在想要强制作为关键字参数的参数前使用星号。或者,如下所示,在所有参数之前,强制所有参数都是关键字参数:

>>> 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
>>>

当您开发某种类型的库时,这个高级函数技巧可能会派上用场。也许你还不想坚持某个论点的顺序。在这种情况下,这是强制库的用户使用命名参数的方法,使顺序变得无关紧要。

使用*和**作为函数参数

有些函数需要很长的参数列表。虽然这应该完全避免,例如,通过使用数据类,但这并不总是由你决定。在这种情况下,第二个最好的选择是创建一个包含所有命名参数的字典,并将其传递给函数。这通常会使您的代码更具可读性。您可以通过使用前缀**来解包字典,以便与命名的关键字一起使用:

>>> def f(a, b):
...     print(a, b)
...
>>> args = { "a": 1, "b": 2 }
>>> f(**args)
1 2

类似地,我们可以使用单个*来解包一个列表,并将其内容作为位置参数提供给一个函数:

>>> def f(a, b, c):
...    print(a, b, c)
...
>>> l = [1, 2, 3]
>>> f(*l)
1 2 3

装饰您的功能

装饰器是一个函数的包装器它以某种方式修改函数的行为。decorators 有许多用例,您可能以前在使用 Flask 这样的框架时使用过。

让我们创建自己的装饰器;它比你想象的要简单,也许有一天会派上用场:

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,我们将装饰器应用于一个函数。也许没有必要说:这个装饰器也可以在其他函数中重用。

我们的小脚本的输出将是:

Argument for add_one is 1
2

匿名函数

有时候命名一个函数是不值得的。一个例子是当你确定函数只会被使用一次。对于这种情况Python 为我们提供了匿名函数,也称为 lambda 函数。

lambda 函数可以赋给一个变量,从而创建了一种简洁的函数定义方式:

>>> add_one = lambda x: x + 1
>>> add_one(3)
4

当你需要使用一个函数作为参数时,这就变得更有趣了。在这种情况下,该函数通常只使用一次。如您所知,map将一个函数应用于一个可迭代对象的所有元素。我们可以在调用 map 时使用 lambda:

>>> numbers = [1, 2, 3, 4]
>>> times_two = map(lambda x: x * 2, numbers)
>>> list(times_two)
[2, 4, 6, 8]
>>>

事实上,这是一种你会经常看到的模式。当你需要对一个 iterable 对象的每个元素应用一个相对简单的操作时,结合 lambda 函数使用map()既简洁又高效。