python 函数定义学习
2020-06-17 本文已影响0人
fdsun
定义函数
- 我们可以创建一个输出任意范围内 Fibonacci 数列的函数:
>>> def fib(n): # write Fibonacci series up to n
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> # Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
- 关键字
def
引入一个函数 定义。它必须后跟函数名称和带括号的形式参数列表。构成函数体的语句从下一行开始,并且必须缩进。
- 重要警告: 默认值只会执行一次。这条规则在默认值为可变对象(列表、字典以及大多数类实例)时很重要。比如,下面的函数会存储在后续调用中传递给它的参数:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
- 这将打印出
[1]
[1, 2]
[1, 2, 3]
- 如果你不想要在后续调用之间共享默认值,你可以这样写这个函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
函数示例
- 请考虑以下示例函数定义并特别注意 / 和 * 标记:
>>> def standard_arg(arg):
... print(arg)
...
>>> def pos_only_arg(arg, /):
... print(arg)
...
>>> def kwd_only_arg(*, arg):
... print(arg)
...
>>> def combined_example(pos_only, /, standard, *, kwd_only):
... print(pos_only, standard, kwd_only)
- 第一个函数定义 standard_arg 是最常见的形式,对调用方式没有任何限制,参数可以按位置也可以按关键字传入:
>>> standard_arg(2)
2
>>> standard_arg(arg=2)
2
- 第二个函数 pos_only_arg 在函数定义中带有 /,限制仅使用位置形参。:
>>> pos_only_arg(1)
1
>>> pos_only_arg(arg=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got an unexpected keyword argument 'arg'
- 第三个函数 kwd_only_args 在函数定义中通过 * 指明仅允许关键字参数:
>>> kwd_only_arg(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
>>> kwd_only_arg(arg=3)
3
- 而最后一个则在同一函数定义中使用了全部三种调用方式:
>>> combined_example(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given
>>> combined_example(1, 2, kwd_only=3)
1 2 3
>>> combined_example(1, standard=2, kwd_only=3)
1 2 3
>>> combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() got an unexpected keyword argument 'pos_only'
- 最后,请考虑这个函数定义,它的位置参数 name 和 **kwds 之间由于存在关键字名称 name 而可能产生潜在冲突:
def foo(name, **kwds):
return 'name' in kwds
- 任何调用都不可能让它返回 True,因为关键字 'name' 将总是绑定到第一个形参。 例如:
>>> foo(1, **{'name': 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for argument 'name'
>>>
- 但使用 / (仅限位置参数) 就可能做到,因为它允许 name 作为位置参数,也允许 'name' 作为关键字参数的关键字名称:
def foo(name, /, **kwds):
return 'name' in kwds
>>> foo(1, **{'name': 2})
True
- 换句话说,仅限位置形参的名称可以在 **kwds 中使用而不产生歧义。
概括
- 用例将确定要在函数定义中使用的参数:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
- 作为指导:
- 如果你希望形参名称对用户来说不可用,则使用仅限位置形参。 这适用于形参名称没有实际意义,以及当你希望强制规定调用时的参数顺序,或是需要同时收受一些位置形参和任意关键字形参等情况。
- 当形参名称有实际意义,以及显式指定形参名称可使函数定义更易理解,或者当你想要防止用户过于依赖传入参数的位置时,则使用仅限关键字形参。
- 对于 API 来说,使用仅限位置形参可以防止形参名称在未来被修改时造成破坏性的 API 变动。
解包参数列表
- 当参数已经在列表或元组中但要为需要单独位置参数的函数调用解包时,会发生相反的情况。例如,内置的
range()
函数需要单独的 start 和 stop 参数。如果它们不能单独使用,可以使用*
-操作符 来编写函数调用以便从列表或元组中解包参数:
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
- 同样的方式,字典可使用 ** 操作符 来提供关键字参数:
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
Lambda 表达式
- 可以用
lambda
关键字来创建一个小的匿名函数。这个函数返回两个参数的和:lambda a, b: a+b
。Lambda函数可以在需要函数对象的任何地方使用。它们在语法上限于单个表达式。从语义上来说,它们只是正常函数定义的语法糖。与嵌套函数定义一样,lambda函数可以引用所包含域的变量:
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
- 上面的例子使用一个lambda表达式来返回一个函数。另一个用法是传递一个小函数作为参数:
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
文档字符串
以下是有关文档字符串的内容和格式的一些约定。
第一行应该是对象目的的简要概述。为简洁起见,它不应显式声明对象的名称或类型,因为这些可通过其他方式获得(除非名称恰好是描述函数操作的动词)。这一行应以大写字母开头,以句点结尾。
如果文档字符串中有更多行,则第二行应为空白,从而在视觉上将摘要与其余描述分开。后面几行应该是一个或多个段落,描述对象的调用约定,它的副作用等。
Python 解析器不会从 Python 中删除多行字符串文字的缩进,因此处理文档的工具必须在需要时删除缩进。 这是使用以下约定完成的。 文档字符串第一行 之后 的第一个非空行确定整个文档字符串的缩进量。(我们不能使用第一行,因为它通常与字符串的开头引号相邻,因此它的缩进在字符串文字中不明显。)然后从字符串的所有行的开头剥离与该缩进 "等效" 的空格。 缩进更少的行不应该出现,但是如果它们出现,则应该剥离它们的所有前导空格。 应在转化制表符为空格后测试空格的等效性(通常转化为8个空格)。
下面是一个多行文档字符串的例子:
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything.
... """
... pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
参见:其他流程控制工具