Python 函数:函数参数

左手的ㄟ右手 2023-07-15 11:30 33阅读 0赞

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

  1. def say_hello(name):
  2. print('Hello', name)
  3. if __name__ == '__main__':
  4. say_hello('James')

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

默认参数

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

  1. def say_hello(name='Man'):
  2. print('Hello', name)
  3. if __name__ == '__main__':
  4. say_hello()
  5. say_hello('James')

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

可变参数:*args

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

  1. def add_to_sum(args):
  2. total = 0
  3. for i in args:
  4. total += (i * i)
  5. print(total)
  6. if __name__ == '__main__':
  7. l = [1, 2, 3]
  8. add_to_sum(l)
  9. add_to_sum([1, 2, 3])

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

  1. def add_to_sum(*args):
  2. total = 0
  3. for i in args:
  4. total += (i * i)
  5. print(total)
  6. if __name__ == '__main__':
  7. add_to_sum(1, 2, 3)
  8. add_to_sum(2, 4, 6)

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

  1. def add_to_sum(*args):
  2. total = 0
  3. for i in args:
  4. total += (i * i)
  5. print(total)
  6. if __name__ == '__main__':
  7. l = [1, 3, 5]
  8. s = (5, 10, 15, 20)
  9. add_to_sum(*l)
  10. add_to_sum(*s)

关键词参数: **kw

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

  1. def person(**kw):
  2. print('other:', kw)
  3. if __name__ == '__main__':
  4. person()
  5. person(name='James')

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

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

  1. def person(**kw):
  2. print('other:', kw)
  3. if __name__ == '__main__':
  4. extra = {'School': 'UESTC', 'Hobby': 'Basketball'}
  5. person(**extra)

命名关键词参数

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

  1. def person(*, school):
  2. print(school)
  3. if __name__ == '__main__':
  4. extra = {'school': 'UESTC', 'Hobby': 'Basketball'}
  5. person(**extra)
  6. person()

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

  1. def person(*, school):
  2. print(school)
  3. if __name__ == '__main__':
  4. extra = {'school': 'UESTC'}
  5. person()

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

  1. def person(*, school):
  2. print(school)
  3. if __name__ == '__main__':
  4. extra = {'school': 'UESTC'}
  5. person(**extra)

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

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

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

  1. def person(name, age, city, job):
  2. pass

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

参数顺序:

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

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

典例分析:

  1. def f1(a, b, c=0, *args, **kw):
  2. print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3. def f2(a, b, c=0, *, d, **kw):
  4. 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 传入

  1. def f1(a, b, c=0, *args, **kw):
  2. print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3. def f2(a, b, c=0, *, d, **kw):
  4. print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
  5. args = (1, 2, 3, 4)
  6. kw = {'d': 99, 'x': '#'}
  7. f1(*args, **kw)

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

  1. def f1(a, b, c=0, *args, **kw):
  2. print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3. def f2(a, b, c=0, *, d, **kw):
  4. print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
  5. args = (1, 2, 3)
  6. kw = {'d': 88, 'x': '#'}
  7. f2(*args, **kw)

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

  1. def f1(a, b, c=0, *args, **kw):
  2. print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3. def f2(a, b, c=0, *, d, **kw):
  4. print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
  5. args = (1, 2, 3)
  6. kw = {'x': '#'}
  7. f2(*args, **kw)

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

  1. def f1(a, b, c=0, *args, **kw):
  2. print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3. def f2(a, b, c=0, *, d, **kw):
  4. print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
  5. args = (1, 2, 3)
  6. kw = {'x': '#'}
  7. f1(*args, **kw)

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

  1. def f1(a, b, c=0, *args, **kw):
  2. print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3. def f2(a, b, c=0, *, d, **kw):
  4. print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
  5. args = (1,)
  6. kw = {'x': '#'}
  7. f1(*args, **kw)

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

感悟

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

发表评论

表情:
评论列表 (有 0 条评论,33人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Python 函数参数

    使用位置参数 有时候,方法接收的参数数目可能不一定,比如定义一个求和的方法,至少要接收两个参数: def sum(a, b): return a

    相关 python函数参数

    Python的函数定义中除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数 1、必选参数:须以正确的顺序传入函数。调用时的数量必须和声明时的一样。调用函数是必