来源:https://docs.python.org/3.6/tutorial/controlflow.html#the-range-function
>>> 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
引入了一个函数定义。它必须后跟函数名称和带括号的形式参数列表。构成函数体的语句从下一行开始,并且必须缩进。
调用函数调用的实际参数(参数)在被调用函数的本地符号表中引入; 因此,使用call by value传递参数(其中值始终是对象引用,而不是对象的值)。当函数调用另一个函数时,将为该调用创建一个新的本地符号表。
函数定义在当前符号表中引入函数名称。函数名称的值具有解释器将其识别为用户定义函数的类型。此值可以分配给另一个名称,该名称也可以用作函数。这是一般的重命名机制:
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
实际上,即使是没有return
语句的函数也会 返回一个值,尽管它是一个相当无聊的值。调用此值None
(它是内置名称)。None
如果它是唯一写入的值,则解释器通常会禁止写入值。如果你真的想使用它,你可以看到它print()
:
>>> fib(0)
>>> print(fib(0))
None
编写一个函数可以很简单地返回Fibonacci系列的数字列表,而不是打印它:
>>> def fib2(n): # return Fibonacci series up to n
... """Return a list containing the Fibonacci series up to n."""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a) # see below
... a, b = b, a+b
... return result
...
>>> f100 = fib2(100) # call it
>>> f100 # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
像往常一样,此示例演示了一些新的Python功能:
- 该
return
语句返回一个函数的值。return
没有表达式参数返回None
。从函数的末尾掉落也会返回None
。 - 该语句
result.append(a)
调用list对象 的方法result
。方法是“属于”对象并被命名的函数obj.methodname
,其中obj
是某个对象(可能是表达式),并且methodname
是由对象的类型定义的方法的名称。不同类型定义不同的方法。不同类型的方法可以具有相同的名称而不会引起歧义。(可以使用类定义自己的对象类型和方法,请参阅类)append()
示例中显示的方法是为列表对象定义的; 它在列表的末尾添加了一个新元素。在这个例子中它相当于 ,但效率更高。result = result + [a]
更多关于定义函数的信息
也可以使用可变数量的参数定义函数。有三种形式可以组合。
默认参数值
最有用的形式是为一个或多个参数指定默认值。这创建了一个函数,可以使用比定义允许的参数更少的参数调用。例如:
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, only yes or no!')
此示例还介绍了in
关键字。这测试序列是否包含某个值。
默认值在定义范围内的函数定义点进行计算 ,以便进行
i = 5
def f(arg=i):
print(arg)
i = 6
f()
将打印5
。
重要警告: 默认值仅评估一次。当默认值是可变对象(例如列表,字典或大多数类的实例)时,这会产生差异。例如,以下函数会累积在后续调用中传递给它的参数:
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
关键字参数
也可以使用 表单的关键字参数调用函数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, "!")
接受一个所需参数(voltage
)和三个可选参数(state
,action
,和type
)。可以通过以下任何方式调用此函数:
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
但以下所有调用都将无效:
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
在函数调用中,关键字参数必须遵循位置参数。传递的所有关键字参数必须与函数接受的参数之一匹配(例如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
存在表单的最终形式参数时,它接收包含除了与形式参数相对应的所有关键字参数的字典(参见映射类型 - 字典)。这可以与形式的形式参数*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")
当然它会打印:
-- Do you have any Limburger ?
-- I'm sorry, we're all out of 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))
通常,这些variadic
参数将在形式参数列表中排在最后,因为它们会挖掘传递给函数的所有剩余输入参数。在*args
参数之后出现的任何形式参数都是“仅关键字”参数,这意味着它们只能用作关键字而不是位置参数
>>> def concat(*args, sep="/"):
... return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'
解压缩参数列表
当参数已经在列表或元组中但需要为需要单独位置参数的函数调用解包时,会发生相反的情况。例如,内置range()
函数需要单独的 start和stop参数。如果它们不是单独可用的,请使用*
-operator 编写函数调用以 从列表或元组中解压缩参数:
>>> 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]
以相同的方式,字典可以使用**
-operator 提供关键字参数:
>>> 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 !