参考 https://docs.python.org/zh-cn/3.9/tutorial/controlflow.html#more-on-defining-functions

参数默认值

参考 https://docs.python.org/zh-cn/3.9/tutorial/controlflow.html#default-argument-values

如何使用

最有用的形式是对一个或多个参数指定一个默认值。这样创建的函数,可以用比定义时允许的更少的参数调用,比如:

  1. def ask_ok(prompt, retries=4, reminder='Please try again!'):
  2. while True:
  3. ok = input(prompt)
  4. if ok in ('y', 'ye', 'yes'):
  5. return True
  6. if ok in ('n', 'no', 'nop', 'nope'):
  7. return False
  8. retries = retries - 1
  9. if retries < 0:
  10. raise ValueError('invalid user response')
  11. print(reminder)

这个函数可以通过几种方式调用:

  • 只给出必需的参数:ask_ok('Do you really want to quit?')
  • 给出一个可选的参数:ask_ok('OK to overwrite the file?', 2)
  • 或者给出所有的参数:ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

    默认值的赋值时机

    默认值是在 定义过程 中在函数定义处计算的,所以 ```python i = 5

def f(arg=i): print(arg) # 5

i = 6 f()

  1. ```python
  2. i = 5
  3. def f(arg=i):
  4. print(arg) # 6
  5. i = 6
  6. f(i)

这个在上一节《函数的定义和使用》的函数执行流程做过说明,不难理解

重要警告

默认值只会执行一次。这条规则在默认值为可变对象(列表、字典以及大多数类实例)时很重要。比如,下面的函数会存储在后续调用中传递给它的参数:

  1. def f(a, L=[]):
  2. L.append(a)
  3. return L
  4. print(f(1)) # [1]
  5. print(f(2)) # [1, 2]
  6. print(f(3)) # [1, 2, 3]

如何理解

这里强调的是理解,方便记忆,并未确定就是这种原理
默认参数可理解为全局变量,但是全局作用域不能访问,函数作用域可以访问

  1. L1= []
  2. def f(a, L=L1):
  3. L.append(a)
  4. return L
  5. print(f(1)) # [1]
  6. print(f(2)) # [1, 2]
  7. print(f(3)) # [1, 2, 3]
  8. print(L) # NameError: name 'L' is not defined

【关键字参数】

作用:方便函数调用时灵活指定参数,正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数。
注意:在函数调用中,关键字参数必须跟随在位置参数的后面。

  1. def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
  2. print("-- This parrot wouldn't", action, end=' ')
  3. print("if you put", voltage, "volts through it.")
  4. print("-- Lovely plumage, the", type)
  5. print("-- It's", state, "!")

接受一个必需的参数(voltage)和三个可选的参数(state, action,和 type)。这个函数可以通过下面的任何一种方式调用:

  1. parrot(1000) # 1 positional argument
  2. parrot(voltage=1000) # 1 keyword argument
  3. parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
  4. parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
  5. parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
  6. parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword

但下面的函数调用都是无效的:

  1. parrot() # required argument missing
  2. parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
  3. parrot(110, voltage=220) # duplicate value for the same argument
  4. parrot(actor='John Cleese') # unknown keyword argument

【特殊参数】

这个知识点作为了解即可,属于新特性,用于对参数做一些限制
参考 https://docs.python.org/zh-cn/3.9/tutorial/controlflow.html#special-parameters

解包参数列表

当参数已经在列表或元组中但要为需要单独位置参数的函数调用解包时,会发生相反的情况。例如,内置的 [range()](https://docs.python.org/zh-cn/3.9/library/stdtypes.html#range) 函数需要单独的 startstop 参数。如果它们不能单独使用,可以使用 * 操作符 来编写函数调用以便从列表或元组中解包参数:

解包列表或元组

  1. >>> list(range(3, 6)) # 使用单独参数的正常调用
  2. [3, 4, 5]
  3. >>> args = [3, 6]
  4. >>> list(range(*args)) # 调用时参数从列表中解包
  5. [3, 4, 5]
  6. >>> args = (3, 6)
  7. >>> list(range(*args)) # 调用时参数从列表中解包
  8. [3, 4, 5]

解包字典

  1. >>> def parrot(voltage, state='a stiff', action='voom'):
  2. ... print("-- This parrot wouldn't", action, end=' ')
  3. ... print("if you put", voltage, "volts through it.", end=' ')
  4. ... print("E's", state, "!")
  5. ...
  6. >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
  7. >>> parrot(**d)
  8. -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

任意的参数列表

最后,最不常用的选项是可以使用任意数量的参数调用函数。这些参数会被包含在一个元组里(参见 元组和序列)。在可变数量的参数之前,可能会出现零个或多个普通参数。

注解:若函数在定义时不确定想传入多少个参数,就可以使用任意的参数列表

*args

  1. def write_multiple_items(file, *args):
  2. print(args)
  3. write_multiple_items(1,2,3) # 输出: (2, 3)
  4. write_multiple_items(1,2,3,4) # 输出: (2, 3, 4)
  1. def write_multiple_items(file, name='ecithy', *args):
  2. print(args, name)
  3. write_multiple_items(1,2,3) # 输出: (3,) 2
  4. write_multiple_items(1,2,3,4) # 输出: (3, 4) 2
  1. # 不推荐这样使用
  2. def write_multiple_items(file, *args, name='ecithy'):
  3. print(args, name)
  4. write_multiple_items(1,2,3) # 输出: (2, 3) ecithy
  5. write_multiple_items(1,2,3,4) # 输出: (2, 3, 4) ecithy

**kwargs

  1. def write_multiple_items(file, **kargs):
  2. print(file, kargs)
  3. write_multiple_items('1.txt', age=18, phone='110')
  4. # 输出: 1.txt {'age': 18, 'phone': '110'}

args + *kwargs

  1. def write_multiple_items(file, *args, **kwargs):
  2. print(file, args, kwargs)
  3. write_multiple_items('1.txt', 1, 2 , age=18, phone='110')
  4. # 输出: 1.txt (1, 2) {'age': 18, 'phone': '110'}

总结

一般用法:普通参数(位置参数、默认参数放在前,任意的参数列表放在最后
注意:

  • *args**kargs中的argskargs不是固定写法,但是一般这样写
  • *args 会把多传入的参数变成一个元组形式,**kargs会把多传入的参数变成一个字典形式

    解包参数列表+任意的参数列表

    推荐这种写法,原因如下:

  • 语法间接

  • 便于记忆:形参和实参参数符号一致(均为、*)

    *args

    ```python def write_multiple_items(file, *args): print(file, args)

t = (18, ‘110’)

write_multiple_items(‘1.txt’, *t)

输出: 1.txt (18, ‘110’)

  1. <a name="UJgEZ"></a>
  2. ### **kargs
  3. ```python
  4. def write_multiple_items(file, **kargs):
  5. print(file, kargs)
  6. d = dict(
  7. age=18, phone='110'
  8. )
  9. write_multiple_items('1.txt', **d)
  10. # 输出: 1.txt {'age': 18, 'phone': '110'}

args + *kwargs

  1. def write_multiple_items(file, *args, **kwargs):
  2. print(file, args, kwargs)
  3. t = (18, '110')
  4. d = dict(
  5. age=18, phone='110'
  6. )
  7. write_multiple_items('1.txt', *t, **d)
  8. # 输出: 1.txt (18, '110') {'age': 18, 'phone': '110'}