python11:函数,,当你需要编写大型程序


当你需要编写大型程序时,你可能想要写一段代码供其它地方调用,或者将程序中的相同逻辑抽出来,这时你就需要用到函数。但函数不仅能提供这些功能,通过使用函数还能帮助我们更容易的理解代码。

定义函数

下面的代码定义了一个函数fib,用于计算Fibonacci数列:

>>> def fib(n):        """Print a Fibonacci series up to n."""a, b = 0, 1while a < n:print(a, end=' ')a, b = b, a+bprint()>>> fib(200)0 1 1 2 3 5 8 13 21 34 55 89 144 
首先是关键词def,后面跟函数名和参数列表。从下一行开始就是函数的主体,必须缩进。
函数的第一行可以是描述性的字符串,可选,如果有,则会作为函数的一部分进行存储,成为文档字符串。有工具可以使用文档字符串自动生成在线或者打印的文档,也可以通过下面的方式访问:

>>> fib.__doc__'Print a Fibonacci series up to n.'
或者使用help函数:

>>> help(fib)Help on function fib in module __main__:fib(n)    Print a Fibonacci series up to n.
函数可以使用return返回一个值,例如,为上面的fib函数返回一个结果序列:

>>> def fib2(n):"""Return a list containing the Fibonacci series up to n."""result = []a, b = 0, 1while a < n:result.append(a)a, b = b, a+breturn result>>> f100 = fib2(100)>>> f100[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
如果函数没有return语句,则返回None,如:

>>> f100 = fib(100)0 1 1 2 3 5 8 13 21 34 55 89 >>> print(f100)None
下面介绍更多python中函数的更多特性。

为参数指定默认值

为函数参数指定默认值非常有用,这样在调用该函数时可以指定更少的参数,例如:

>>> def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):while True:ok = input(prompt)if ok in ('y', 'ye', 'yes'):return Trueif ok in ('n', 'no', 'nop', 'nope'):return Falseretries = retries - 1if retries < 0:raise OSError('uncooperative user')print(complaint)
该函数你可以通过下面的方式调用:
1)仅指定强制参数:

>>> ask_ok('Do you really want to quit?')Do you really want to quit?yTrue
2)给可选参数中的一个:

>>> ask_ok('OK to overwrite the file?', 2)OK to overwrite the file?nFalse
3)给出所有参数:

>>> ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')OK to overwrite the file?nFalse
需要注意的是,函数的默认值在定义的一刻就确定了,例如:

>>> i = 5>>> def f(arg=i):print(arg)>>> i = 6>>> f()5
由于定义f的时候i的值为5,所以调用f()总是打印5。

警告:默认值只会赋值一次,但当默认值是一个可变对象时(例如list、字典、或者可变类的实例),将可能存在问题,看下面的例子,将传入的值累计在了一起:

>>> def f(a, L=[]):L.append(a)return L>>> print(f(1))[1]>>> print(f(2))[1, 2]>>> print(f(3))[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, "!")
parrot指定了一个强制参数和3个可选参数。parrot可以使用下面的形式调用:

parrot(1000)parrot(voltage=1000)parrot(voltage=1000000, action='VOOOOOM')parrot(action='VOOOOOM', voltage=1000000)parrot('a million', 'bereft of life', 'jump')parrot('a thousand', state='pushing up the daisies')
注意下面的调用方式是无效的:

parrot()parrot(voltage=5.0, 'dead')parrot(110, voltage=220)parrot(actor='John Cleese')

可变长度参数

函数支持可变长度参数,传入的参数将被打包为一个元组,在可变参数之前,0个或者多个参数可以提供。

>>> def write_multiple_items(file, separator, *args):file.write(separator.join(args))
*args表示可以输入任意个参数。通常,可变参数都会放到参数列表的最后,因为他们将包括所有后面的输入参数。任何可变参数后面的参数都必须以关键字参数的形式使用。下面看一个具体的例子:

>>> def concat(*args, sep="/"):    return sep.join(args)>>> concat("earth", "mars", "venus")'earth/mars/venus'>>> concat("earth", "mars", "venus", sep=".")'earth.mars.venus'
除了‘*‘,python还支持‘**‘。‘**‘表示传入的参数为字典,看下面的例子:

>>> def print_params(**params):print(params)>>> print_params(x=1,y=2,z=3){'z': 3, 'x': 1, 'y': 2}
这样,打印出params为一个字典。下面看一个综合的例子:

>>> 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)keys = sorted(keywords.keys())for kw in keys: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 LimburgerIt's very runny, sir.It's really very, VERY runny, sir.----------------------------------------client : John Cleeseshopkeeper : Michael Palinsketch : Cheese Shop Sketch

解包list和元组

前面已经使用‘*‘和‘**‘将传入参数打包为一个元组和字典,但如果参数已经为一个list或者元组,怎么将其作为参数传入函数呢?可以使用‘*‘和‘**‘来将其解包。看下面的例子:

>>> args = [3, 6]>>> list(range(*args))[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本身和标准库都不使用函数注释,这里展示一下函数注释的语法。
注释被存储在函数的__annotations__属性中,参数注释通过参数后面加一个冒号定义,被一个表达式跟随;返回注释通过语法->定义。下面是一个例子:

>>> def f(ham: 42, eggs: int = 'spam') -> "Nothing to see here":print("Annotations:", f.__annotations__)print("Arguments:", ham, eggs)>>> f('wonderful')Annotations: {'return': 'Nothing to see here', 'ham': 42, 'eggs': <class 'int'>}Arguments: wonderful spam

作用域

python中变量被放在一个字典中,通过“名称->值”的形式存储。内建的vars函数可以返回这个字典:

>>> x = 1>>> scope = vars()>>> scope['x']1
这种字典就叫做命名空间或者作用域。每个函数调用都会创建一个新的作用域,函数内的变量被称为局部变量,参数类似于局部变量。
python中提供了方法在函数中访问全局变量,可以使用globals函数获取全局变量值,该函数的近亲是vars,例如:

>>> def combine(parameter):print(parameter + globals()['parameter'])>>> parameter = 'berry'>>> combine('Shrub')Shrubberry
也可以使用绑定全局变量的方法:

>>> x = 1>>> def change_global():global xx = x + 1>>> change_global()>>> x2
但这样容易导致混乱,建议尽量不要这样做。

python11:函数

评论关闭