函数¶
函数可以帮助程序员将逻辑封装成一个任务,以避免代码重复。在 Python 中,函数的定义非常灵活,我们可以使用许多特性,例如装饰器、注解、文档字符串、默认参数等等来定义函数。本速查表收集了多种定义函数的方式,并揭示了函数中一些神秘的语法。
函数文档¶
文档为程序员提供了关于函数如何使用的提示。文档字符串提供了一种便捷的方式来编写函数的可读文档。PEP 257 定义了一些文档字符串的约定。为了避免违反约定,有一些工具,例如 doctest 或 pydocstyle 可以帮助我们检查文档字符串的格式。
>>> def example():
... """This is an example function."""
... print("Example function")
...
>>> example.__doc__
'This is an example function.'
>>> help(example)
默认参数¶
在 Python 中,定义一个函数,其中参数是可选的并具有默认值非常简单。我们只需在定义中分配值,并确保默认参数出现在最后。
>>> def add(a, b=0):
... return a + b
...
>>> add(1)
1
>>> add(1, 2)
3
>>> add(1, b=2)
3
可选参数¶
>>> def example(a, b=None, *args, **kwargs):
... print(a, b)
... print(args)
... print(kwargs)
...
>>> example(1, "var", 2, 3, word="hello")
1 var
(2, 3)
{'word': 'hello'}
解包参数¶
>>> def foo(a, b, c='BAZ'):
... print(a, b, c)
...
>>> foo(*("FOO", "BAR"), **{"c": "baz"})
FOO BAR baz
仅限关键字参数¶
Python 3.0 新增
>>> def f(a, b, *, kw):
... print(a, b, kw)
...
>>> f(1, 2, kw=3)
1 2 3
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
注解¶
Python 3.0 新增
注解可以是一种有用的方式,可以为程序员提供有关参数类型的提示。此功能的规范在 PEP 3107 中。Python 3.5 引入了 typing
模块来扩展类型提示的概念。此外,从 3.6 版本开始,Python 开始提供了一种通用方式来定义带注解的变量。更多信息可以在 PEP 483、PEP 484 和 PEP 526 中找到。
>>> def fib(n: int) -> int:
... a, b = 0, 1
... for _ in range(n):
... b, a = a + b, b
... return a
...
>>> fib(10)
55
>>> fib.__annotations__
{'n': <class 'int'>, 'return': <class 'int'>}
可调用对象¶
在某些情况下,例如传递回调函数,我们需要检查对象是否可调用。内置函数 callable
帮助我们避免在对象不可调用时引发 TypeError
。
>>> a = 10
>>> def fun():
... print("I am callable")
...
>>> callable(a)
False
>>> callable(fun)
True
获取函数名称¶
>>> def example_function():
... pass
...
>>> example_function.__name__
'example_function'
Lambda 表达式¶
有时,我们不想使用 def 语句来定义一个简短的回调函数。我们可以使用 lambda
表达式作为快捷方式来定义匿名函数或内联函数。但是,在 lambda
中只能指定一个单一的表达式。也就是说,不能包含其他特性,例如多行语句、条件或异常处理。
>>> fn = lambda x: x**2
>>> fn(3)
9
>>> (lambda x: x**2)(3)
9
>>> (lambda x: [x*_ for _ in range(5)])(2)
[0, 2, 4, 6, 8]
>>> (lambda x: x if x>3 else 3)(5)
5
生成器¶
>>> def fib(n):
... a, b = 0, 1
... for _ in range(n):
... yield a
... b, a = a + b, b
...
>>> [f for f in fib(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
装饰器¶
Python 2.4 新增
PEP 318 - 函数和方法的装饰器
>>> from functools import wraps
>>> def decorator(func):
... @wraps(func)
... def wrapper(*args, **kwargs):
... print("Before calling {}.".format(func.__name__))
... ret = func(*args, **kwargs)
... print("After calling {}.".format(func.__name__))
... return ret
... return wrapper
...
>>> @decorator
... def example():
... print("Inside example function.")
...
>>> example()
Before calling example.
Inside example function.
After calling example.
等价于
... def example():
... print("Inside example function.")
...
>>> example = decorator(example)
>>> example()
Before calling example.
Inside example function.
After calling example.
带参数的装饰器¶
>>> from functools import wraps
>>> def decorator_with_argument(val):
... def decorator(func):
... @wraps(func)
... def wrapper(*args, **kwargs):
... print("Val is {0}".format(val))
... return func(*args, **kwargs)
... return wrapper
... return decorator
...
>>> @decorator_with_argument(10)
... def example():
... print("This is example function.")
...
>>> example()
Val is 10
This is example function.
等价于
>>> def example():
... print("This is example function.")
...
>>> example = decorator_with_argument(10)(example)
>>> example()
Val is 10
This is example function.
缓存¶
Python 3.2 新增
无缓存
>>> import time
>>> def fib(n):
... if n < 2:
... return n
... return fib(n - 1) + fib(n - 2)
...
>>> s = time.time(); _ = fib(32); e = time.time(); e - s
1.1562161445617676
有缓存(动态规划)
>>> from functools import lru_cache
>>> @lru_cache(maxsize=None)
... def fib(n):
... if n < 2:
... return n
... return fib(n - 1) + fib(n - 2)
...
>>> s = time.time(); _ = fib(32); e = time.time(); e - s
2.9087066650390625e-05
>>> fib.cache_info()
CacheInfo(hits=30, misses=33, maxsize=None, currsize=33)