函数进阶

位置参数

位置参数这个东西我们并不陌生,之前所编写的函数使用的就是位置参数。位置参数,顾名思义,传入函数时每个参数都是通过位置来作区分的。函数调用时,传入的值需按照位置与参数一一对应。

比如:

def overspeed_rate(current, max, min):
    if current > max:
        return (current - max) / max    # 超过最大时速,结果为正
    elif current < min:
        return (current - min) / min    # 超过最小时速,结果为负
    else:
        return 0                        # 不超速,结果为 0

这个函数用来判断车辆在高速上行驶时超速的比例。它接受三个参数,current 表示当前时速,max 参数表示当前路段的允许的最大时速,min 表示所允许的最小时速。

位置参数需要按位置顺序来传递,否则结果不可预期。

>>> overspeed_rate(150, 120, 90)
0.25 # 超过最大时速 25%
>>> overspeed_rate(80, 100, 60)
0 # 不超速
>>> overspeed_rate(60, 120, 90)
-0.3333333333333333 # 超过最小时速 33.33%

参数默认值

前面的函数中,如果最大时速和最小时速比较固定,那么每次函数调用时都输入这个两个参数就显得有些繁琐,这时我们可以使用参数默认值。

参数默认值也就是给参数设置默认值,之后函数调用时便可以不传入这个参数,Python 自动以默认值来填充参数。如果一个有默认值的参数依然被传入了值,那么默认值将会被覆盖。

函数定义时,以 参数=值 来指定参数默认值。如下:

def 函数(参数1, 参数2=默认值):
    pass
例如上面的 overspeed_rate 函数, max 和 min 通常比较固定,我们可以使用一个常用值来作为默认值。

def overspeed_rate(current, max=120, min=90):
    if current > max:
        return (current - max) / max
    elif current < min:
        return (current - min) / min
    else:
        return 0
>>> overspeed_rate(192)
0.6
>>> overspeed_rate(45)
-0.5

关键字参数

对于 overspeed_rate 函数,我们还可以在函数调用时,以 参数名=值 的形式来向指定的参数传入值。

如:

overspeed_rate(100, min=80)

或者

overspeed_rate(current=100, min=80)

或者

overspeed_rate(current=100, max=100, min=80)

在调用函数时以 参数名=值 指明要传递的参数,这种以关键字的形式来使用的参数叫做关键字参数。

使用关键字时甚至可以打乱参数传递次序:

overspeed_rate(min=80, max=100, current=100)
>>> overspeed_rate(min=80, max=100, current=100)
0

但要注意,关键字参数需要出现在位置参数之后,否则将抛出 SyntaxError 异常:

>>> overspeed_rate(100, max=100, 80)
     File “”, line 1
SyntaxError: positional argument follows keyword argument

关键字参数的用法还不止如此。

当我们在定义函数时,如果参数列表中某个参数使用 **参数名 形式,那么这个参数可以接受一切关键字参数。如下:

def echo(string, **keywords):
    print(string)
    for kw in keywords:
        print(kw, ":", keywords[kw])
>>> echo(‘hello’, today=‘2019-09-04’, content=‘function’, section=3.6)
hello
today : 2019-09-04
content : function
section : 3.6

显然,我们并没有在函数定义时定义 today、content、section 参数,但是我们却能接收到它们,这正是 **keywords 发挥了作用。函数会将所有接收到的关键字参数组装成一个字典,并绑定到 keywords 上。验证一下:

>>> def foo(**keywords):
…     print(keywords)
…
>>> foo(a=1, b=2, c=3)
{‘a’: 1, ‘b’: 2, ‘c’: 3}

任意参数列表

定义函数时,在参数列表中使用**参数名,可以接收一切关键字参数。类似的,参数列表中使用 *参数名,就可以接受任意数量的非关键字参数,也就是可变参数。

如,计算任意个数的乘积:

def multiply(*nums):
    result = 1
    for n in nums:
        result *= n
    return result
>>> multiply(1,3,5,7)
105

这个函数能接收任意个参数,这正是 *nums 所发挥的作用。函数所有接收到的非关键字参数组装成一个元组,并绑定到 nums 上。来试验一下:

>>> def multiply(*nums):
…     print(nums)
…
>>> multiply(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5)

多返回值

典型情况下,函数只有一个返回值,但是 Python 也支持函数返回多个返回值。

要返回多个返回值,只需在 return 关键字后跟多个值(依次用逗号分隔)。

例如:

def date():
    import datetime
    d = datetime.date.today()
    return d.year, d.month, d.day
date() 返回了今天的日期的年、月、日。

接收函数返回值时,用对应返回值数量的变量来分别接收它们。

>>> year, month, day = date()
>>> year
2019
>>> month
9
>>> day
4

函数返回多个返回值是什么原理呢?其实多返回值时,Python 将这些返回值包装成了元组,然后将元组返回。来验证下:

>>> date()
(2019, 9, 4)

接收返回值时,year, month, day = date(),这样赋值写法,会将元组解包,分别将元素赋予单独的变量中。即:

>>> year, month, day = (2019, 9, 4)
>>> year
2019
>>> month
9
>>> day
4

results matching ""

    No results matching ""