Python 函数的参数

python 函数的参数可分为位置参数、缺省参数、可变参数和关键字参数。其中可变参数和关键字参数又可以进行拆包。

位置参数

看下面程序:

    def fun1(a, b):
        print("a -- " + str(a))
        print("b -- " + str(b))
        return a + b

    print(fun1(2, 3))

显然,程序结果:

    a ---- 2
    b ---- 3
    5

这里的函数 fun1 中的参数 a 和 b 就是位置参数。位置参数在调用时,必须给到具体值。

缺省参数

看下面的代码:

    def fun2(a, b, c=0):
        print("a -- " + str(a))
        print("b -- " + str(b))
        print("c -- " + str(c))
        return a + b + c

    print(fun2(2, 3))
    print(fun2(2, 3, 4))

程序输出结果:

    a -- 2
    b -- 3
    c -- 0
    5
    a -- 2
    b -- 3
    c -- 4
    9

这里函数 fun2 中,有三个参数,其中 a 和 b 是位置参数, c 即是一个缺省参数。声明函数 fun2 时指定了参数 c=0 ,表示参数 c 的默认值是 0 ,上面程序中两次在调用 fun2 时,分别传入了两个参数和三个参数。我们看到,在传入两个参数时,a 和 b 的值分别是传入的 2 和 3,其中 c 的值为默认值 0 ,在传入三个参数时,a, b 和 c
值分别是传入的 2, 3, 4 。
很好理解,在函数定义的时候,给参数赋了一个默认值,这样的参数就叫缺省参数,也叫默认参数。
假设有多个缺省参数,而我只传入了部分缺省参数会是怎样的情况?看下面的程序:

    def fun2(a, b, c=0, d=0):
        print("a -- " + str(a))
        print("b -- " + str(b))
        print("c -- " + str(c))
        print("d -- " + str(d))
        return a + b + c + d

    print(fun2(2, 3, 4))

程序执行结果如下:

    a -- 2
    b -- 3
    c -- 4
    d -- 0
    9

说明,前面的位置参数是必须要传入的,c 的值是 4 ,而 d 的值是默认值 0 ,这说明,传入的部分缺省参数会按顺序赋值。如果偏要将 4 赋给 d ,而 c 用默认参数呢,则用下面方式调用函数即可:
print(fun2(2, 3, d=4))
程序结果:

    a -- 2
    b -- 3
    c -- 0
    d -- 4
    9

不止是缺省参数,位置参数也可以在调用函数时,也可以指定具体的值赋给哪个参数。

值得注意的是:定义函数时缺省参数要放在位置参数后面,如果向下面这样定义:

    def fun2(a, b=0, c):
        return a + b + c

则会报错:SyntaxError: non-default argument follows default argument

熟悉 java、C# 或者 C++ 等语言的应该知道“重载方法”的概念。参数列表不相同,包括参数的类型不相同和参数的个数不相同。在python中,用缺省参数,正好可以实现重载类似的效果。

可变参数(不定长参数)

在Python函数中,还可以定义可变参数,也叫不定长参数。顾名思义,可变参数就是传入的参数个数是可变的,写法为,在参数前面加上一个 * ,类似于 java 中的不定长参数。不同的是,java中不定长参数,以数组形式存储,在python中,可变参数则是一个元组。看下面的程序:

    def fun3(a, *b):
        print(type(a))
        print(a)
        print(type(b))
        print(b)

    fun3(1, 2, 3, 4, 5)

输出结果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, 3, 4, 5)

程序中,函数 fun3 的参数 a 是一个 int 型,后面 *b 即为可变参数,在调用时,可以根据需要传入不同个数的参数,除去 a 之后,剩余所有的参数,都添加到一个元组中。

看下面的调用:
fun3(1, 2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
输出结果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)

结果显示很明确了,即便我传入列表,元组,字典类型的参数,也会被当做元组的元素,添加进去。
约定俗成,函数中的可变参数一般用 *args 来表示。

关键字参数

最后说说 python 的关键字参数。python 关键字参数是在参数前面加上 ** ,和可变参数有点类似,区别在于,关键字参数是以字典形式存储。调用的时候也有区别,看下面的程序:

    def fun4(a, *b, **c):
        print(type(c))
        print(a)
        print(b)
        print(c)

    fun4(1, 2, 3, 4, 5, x=6, y=7)

程序结果:

    <class 'dict'>
    1
    (2, 3, 4, 5)
    {'x': 6, 'y': 7}

结果显示,参数 C 的类型是 dict 字典。在调用时,需要按照 key = value 的形式传入关键字参数。约定俗成,关键字参数一般用 **kwargs 来表示。按照上面的写法,我们调用函数时可以随意传入关键字参数,有时候,我们需要限定关键字参数的 'key' ,这样我们可以使用命名关键字参数。比如,上面的程序,我在调用时关键字参数,传入了 'x' 和 'y',事实上,我想的话,还可以传入更多的参数 ,用命名关键字参数,则可以限定,只传入 'x' 和 'y' ,程序如下:

    def fun5(a, *, x, y):
        print(a)
        print(x)
        print(y)


    fun5(1, x=2, y=3)

输出结果:

    1
    2
    3

即用一个 *,,后面跟上指定的参数。这样,你如果多传,或者少穿关键字参数,都是不可以的。

可变参数和关键字参数拆包

再回头看前面的例子:

    def fun3(a, *b):
        print(type(a))
        print(a)
        print(type(b))
        print(b)

    fun3(1, 2, 3, 4, 5)

执行 fun3(1, 2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
输出结果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)

这里,传入参数的 (3,4,5) 和 [6,7] 和 {'x': 8, 'y': 9} 都被当作元组里面的元素了。下面在调用时,参数前面添加一个 * ,如下:
fun3(1, 2, *(3, 4, 5), *[6, 7], *{'x': 8, 'y': 9}, 10, 11)

结果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, 3, 4, 5, 6, 7, 'x', 'y', 12, 13)

看结果,在列表或者元组参数前面添加 * 之后,却反而被拆开成单个元素,作为元组的元素。而字典,只是把它的 'key' 拆成单个元素。这就是可变参数的拆包。一般,可变参数的拆包我们只针对元组和列表,不针对字典。
同样,对于含有关键字参数的函数,也可对传入的参数进行拆包,看下面这个函数:

    def fun6(**kwargs):
        print(kwargs)

下面我调用函数 fun6({'x': 1, 'y': 2}) ,这时候,程序会报错

因为,关键字参数,在调用的时候传参,需要按照 key = value 的形式传入。而我现在传入一个字典,会被当做一个整体,作为一个位置参数传入。如果以下面这种方式
fun6(**{'x': 1, 'y': 2})
调用,则可行,结果如下:

    {'x': 1, 'y': 2}

即通过 ** 将字典拆成了 'x'=1 , 'y'=2 的形式。这就是关键字参数的拆包。

posted @ 2018-04-17 22:05  SharpCJ  阅读(649)  评论(0编辑  收藏  举报