Python 函数:函数参数

首先给出一个最基本的函数:

def say_hello(name):
    print('Hello', name)


if __name__ == '__main__':
    say_hello('James')

运行结果
在这里插入图片描述

默认参数

在我们的例子中,如果我们不知道他人的名称,如何向他人 say_hello 呢。这个就可以用默认参数,例如一般情况是和男士打招呼(程序媛太少了呀),代码如下

def say_hello(name='Man'):
    print('Hello', name)


if __name__ == '__main__':
    say_hello()
    say_hello('James')

运行结果:
在这里插入图片描述
可以看到,如果我们没有像函数传递参数,函数参数就是取默认值 Man,如果传递了参数,传递的参数就会覆盖掉默认值。
默认参数一般设置为很少修改的参数变量。

可变参数:*args

如果我们相求一个 list 的平方和,一种实现是:

def add_to_sum(args):
    total = 0
    for i in args:
        total += (i  *  i)
    print(total)


if __name__ == '__main__':
    l = [1, 2, 3]
    add_to_sum(l)
    add_to_sum([1, 2, 3])

我们发现每次调用函数都要构建一个 list 或者 tuple 之类的可迭代对象。我们可以使用可变参数来换一种方式。

def add_to_sum(*args):
    total = 0
    for i in args:
        total += (i * i)
    print(total)


if __name__ == '__main__':
    add_to_sum(1, 2, 3)
    add_to_sum(2, 4, 6)

这样就可以直接输入任意可变长度的参数(即,可变参数)。可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
当然如果想要传一个 list 变量也可以的,只需要在调用函数的时候在函数变量之前加一个*即可。

def add_to_sum(*args):
    total = 0
    for i in args:
        total += (i * i)
    print(total)


if __name__ == '__main__':
    l = [1, 3, 5]
    s = (5, 10, 15, 20)
    add_to_sum(*l)
    add_to_sum(*s)

关键词参数: **kw

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def person(**kw):
    print('other:', kw)


if __name__ == '__main__':
    person()
    person(name='James')

关键词参数和可变参数的不同点在于:关键词参数传入的是一个 dict,即含有参数名和值;可变参数传入的是一个 tuple。相同点都是任意长度(包括 0 个)。

同样的,如果想直接将一个 dict 类型的变量传入函数作为关键词参数,那么和可变长参数类似,变量名之前加 **。

def person(**kw):
    print('other:', kw)


if __name__ == '__main__':
    extra = {'School': 'UESTC', 'Hobby': 'Basketball'}
    person(**extra)

命名关键词参数

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收 school 作为关键字参数。命名关键字参数需要一个特殊分隔符 *,* 后面的参数被视为命名关键字参数

def person(*, school):
    print(school)


if __name__ == '__main__':
    extra = {'school': 'UESTC', 'Hobby': 'Basketball'}
    person(**extra)
    person()

这个时候运行会报错,因为我们多输入一个名为 Hobby 的参数。
在这里插入图片描述
如果我们不填命名关键词参数呢:

def person(*, school):
    print(school)


if __name__ == '__main__':
    extra = {'school': 'UESTC'}
    person()

也会报错,也就是说命名关键词参数是必填的!
在这里插入图片描述

def person(*, school):
    print(school)


if __name__ == '__main__':
    extra = {'school': 'UESTC'}
    person(**extra)

在这里插入图片描述
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符 * 了:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

这个函数里面 args 是可变参数,city 和 job 就是命名关键词参数。
命名关键字参数可以有缺省值,和默认值参数一样的使用方法。
使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数。

def person(name, age, city, job):
    pass

例如这里的 city 和 job 都是一般形式的位置参数。

参数顺序:

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

廖雪峰老师博客中一个问题:为什么默认参数要在必选参数之后,不能先默认参数后必选参数。原因其实很简单:这样子如果传一个参数,如何确定是根据位置来的必选参数呢还是默认参数呢。

典例分析:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

1. f1(1, 2)

显然 1 和 2 是位置必选参数,可变参数和关键词参数都为空
a = 1 b = 2 c = 0 args = () kw = {}

2. f1(1, 2, c=3)

显然 1 和 2 是位置必选参数,c=3 显示的替换了默认值
在这里插入图片描述

3. f1(1, 2, 3, ‘a’, ‘b’)

显然 1, 2 和 3 是位置必选参数。‘a’ 和 ‘b’ 都不是键值对形式,显然就是可变长参数。
在这里插入图片描述

4. f1(1, 2, 3, ‘a’, ‘b’, x=99)

显然 1, 2 和 3 是位置必选参数。‘a’ 和 ‘b’ 都不是键值对形式,显然就是可变长参数。x=99 是键值对形式,显然就是关键词参数。
在这里插入图片描述

5. f2(1, 2, d=99, ext=None)

显然 1 和 2 是位置必选参数,c 没有赋值,显然就是取默认值。* 之后就是命名关键词参数,ext = None 是键值对形式,就是关键词参数。
在这里插入图片描述

6. 通过 tuple 或 list 传入

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)

这个将 args 拆开之后先要填充必选项(包括默认参数),然后才是变长参数。类似的先将 kw 拆开之后填充命名关键词参数,再是关键词参数。
所以结果如下:
在这里插入图片描述

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


args = (1, 2, 3)
kw = {'d': 88, 'x': '#'}
f2(*args, **kw)

同样的分析:args 拆开之后去赋值必选的参数(包括默认参数)。类似的先将 kw 拆开之后填充命名关键词参数,再是关键词参数。
结果如下:
在这里插入图片描述
一个问题就是如果 kw 变量里面没有 d 这个键值对,情况如何啊:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


args = (1, 2, 3)
kw = {'x': '#'}
f2(*args, **kw)

显然,代码会报错,理由如上, 命名关键词参数为必填的。
在这里插入图片描述
再一个问题,如果传入的 tuple 仅够填充必填字段呢:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


args = (1, 2, 3)
kw = {'x': '#'}
f1(*args, **kw)

显然是可以的,可变长参数实际传入为空。
在这里插入图片描述
再一个问题,如果传入的 tuple 不够填充必填字段呢:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


args = (1,)
kw = {'x': '#'}
f1(*args, **kw)

显然也是会报错的:
在这里插入图片描述

感悟

* 和 ** 变量对应 tuple 和 dict,但是不一定完全对应可变长参数和关键词参数。在 * 中拆开之后先要填充必填的位置参数和默认参数,填充完成之后剩余的才是可变长参数,当然如果填充不够必填参数会报错。类似的 ** 拆开之后要先赋值命名关键词参数,赋值之后剩余的才是关键词参数,当然如果没有命名关键词对应的 key,也是报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值