定义函数
我们通过斐波那契数列来理解定义函数
>>> def fib(n): # 将斐波那契数列打印到 n
... """将斐波那契数列打印到 n"""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> # 调用上面定义的函数
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字 def 引入了一个函数定义 。
其后面必须跟随有函数的名称以及用括号包起来的一系列参数。构成函数体的语句从下一行开始,并且必须缩进。
函数体的第一个语句可以是一个字符串常量,这个字符串常量就是这个函数的文档字符串,或者说是 docstring ,有很多工具可以用于在线或者可打印文档的自动化生成,或者可以让用户交互地在代码中浏览文档;在代码中写文档字符串是比较好的实践,所以请养成写文档字符串的习惯。
函数的执行引入了一个新的符号表用于存储函数的局部变量
。更准确地说,在函数内的所有变量赋值都会被存储到这张局部符号表中;所以在查找一个变量的引用时,会先查找局部符号表,然后查找闭包函数的局部符号表,接着是全局符号表,最后才是内置名称表。因此,尽管可能在函数中引用全局变量,但在函数中无法对全局变量直接进行赋值(除非用 global 语句来定义一个变量)
调用函数时,将函数参数引入局部符号表;因此,参数是按值传递的(值表示对对象的引用,而不是对象的值)。 [1] 当一个函数调用另一个函数时,会为调用创建一个新的本地符号表。
函数定义将在当前符号表中引入函数的名称。与此函数名称对应的值的类型将被解释器解释为用户定义的函数。这个值可以赋值给另一个名字,这个名字可以作为一个函数使用。这是一种常用的重命名机制:
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
默认参数值
最常见的形式是为一个或多个参数指定默认值。通过这种方式,可以使用比定义的更少的参数调用函数。例如:
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
该函数可以有几种不同的调用方式:
只指定强制的参数
参数: ask_ok('Do you really want to quit?')
提供一个可选参数
参数: ask_ok('OK to overwrite the file?', 2)
或者给定全部的参数
参数: ask_ok('OK to overwrite the file?', 2, 'Come on, onlyyes or no!')
上面的例子也顺便提到了 in 关键字。它用于测试某个值是否在一个序列中。
默认值在定义函数时在“定义”的范围内求值(如果函数参数的默认值是变量,则参数的默认值根据函数定义前的变量值确定) , 所以,
i = 5
def f(arg=i):
print(arg)
i = 6
f()
会打印 5.
关键字参数
形如 kwarg=value 形式的参数是 关键字参数。例如,以下函数:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
采用一个必需参数(电压)和三个可选参数(状态、动作和类型)。该函数调用如下:
parrot(1000) # 一个位置参数
parrot(voltage=1000) # 一个关键字参数
parrot(voltage=1000000, action='VOOOOOM') # 2个关键字参数
parrot(action='VOOOOOM', voltage=1000000) # 2个关键字参数
parrot('a million', 'bereft of life', 'jump') # 3个位置参数
parrot('a thousand', state='pushing up the daisies') # 一个位置参数,一个关键字参数
但是下列的所有调用方式都是无效的:
parrot() # 必选参数缺失
parrot(voltage=5.0, 'dead') # 非关键字参数在关键字参数后面
parrot(110, voltage=220) # 同一参数重复赋值
parrot(actor='John Cleese') # 未知关键字参数
在函数调用中,关键字参数必须跟在参数位置之后。传递的所有关键字参数必须匹配函数接受的参数之一。 (例如:actor 不是函数 parrot 中的有效参数),它们的顺序无关紧要。这也包括可选参数(例如 parrot(voltage=1000) 也是有效的)。在没有参数的情况下可以多次获取一个值。以下示例因此失败:
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function() got multiple values for keyword argument 'a'
当最后有一个 **name 形式的参数时,它最终会收到一个字典(参见 Mapping Types --- dict),其中包含除了与形式参数对应的关键字参数之外的所有关键字参数。这可以与 *name 形式的形式参数(在下一小节中描述)组合,它接收包含形式参数列表之外的位置参数的元组。 (*name 必须出现在 **name 之前。)例如,如果我们定义这样的函数:
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
for kw in keywords:
print(kw, ":", keywords[kw])
它可以像这样调用:
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
可变参数
最后,用于指定参数的最不常见的选项是可变数量的参数。参数将被组装成一个元组(请参阅元组和序列)。零个或多个普通参数可能出现在可变参数之前。
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
分离参数列表
当输入参数已经是列表或元组的形式以便调用单独的位置参数时,会发生上述情况的反转。例如,内置函数 range() 需要单独的启动和停止参数。如果输入不是独立参数,则需要使用 * 运算符从列表或元组中提取参数:
>>> list(range(3, 6)) # 正常利用参数调用函数
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # 从列表中提取参数来调用函数
[3, 4, 5]
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)
4
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 如何在python中绘制图片11/29
- ♥ python 输入成绩求平均分08/16
- ♥ python用什么实现报表?12/25
- ♥ 讲解使用Python处理Excel表格10/24
- ♥ python判断是否大于某个值09/01
- ♥ 如何在python中获取当前文件的部分信息?01/06
内容反馈