7

关于 Python 函数声明以及调用方式

 2 years ago
source link: https://gohalo.me/post/python-parameter-methods.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关于 Python 函数声明以及调用方式

2020-11-13 Friday     SoftWare, Python

Python 提供了非常灵活的参数声明以及调用方式,除了最常用的位置参数,还包括了默认值以及关键词匹配方式,而且对于列表、字典很方便展开。

这里详细介绍 Python 的参数声明、调用方式。

Python 中函数声明的时候有四种方式:

  • foobar(a, b, c) 根据位置匹配形参,需要严格保证数量、顺序一致,也是最常见的一种。
  • foobar(a=1, b=2, c=3) 提供了默认值,可以根据关键字传参,无需再关注参数的顺序,例如 foobar(b=5, c=8, a=10);也不再要求参数一致,例如 foobar() 使用默认值,foobar(a=10) 除了参数 a 其它使用默认值。
  • foobar(*args) 可以传入任意参数,参数会添加到 args 元组中,好处是参数长度不再限制,但是本身仍然存在顺序。
  • foobar(**kargs) 同样可传入任意参数,不过是以字典方式传递,不再有顺序的限制。

注意,上述元组和字典声明中的 *** 符号只是一种标识方式,并没有实际的含义;而 argskargs 也只是习惯性的写法,可以换成其它参数。

也可以将上述的四种方式混合使用,也就是 foobar(a, b=2, *args, **kargs) ,需要注意其顺序,允许有些参数不存在,但是必须要确保其顺序。

在通过函数调用参数的时候,有两种方式:A) 关键词参数 (Keyword Argument),也就是 foobar(a=1, b=2) 这种调用方式;B) 位置参数 (Positional Argument) 也被称为非关键词参数 (Non-Keyword Argument),最常用的 foobar(1, 2) 方式,参数位置通过声明已经约束明确好。

注意,这里的调用方式并未与上述的声明 (定义) 方式绑定,例如,如下的示例。

def foo(a, b, c):
        print(a, b, c)
def bar(a=1, b=2, c=3):
        print(a, b, c)
foo(c=3, a=1, b=2)  # (1, 2, 3)
bar(1, 2, 3)        # (1, 2, 3)

不过,传参的时候有个优先级,位置参数需要放到最开始,然后才能使用关键词参数,如下的使用方式是错误的。

def foobar(a, b, c=1):
	print(a, b, c)
#foobar(c=1, 1, 2) # ERROR 需要先使用非关键词参数
#foobar(1, 2, b=3) # ERROR 参数b被赋值了两次

实际上,匹配过程也是按照上述的混合声明的顺序进行,也就是:

  1. 按照顺序匹配位置参数。
  2. 将关键词参数赋值给对应的形参。
  3. 将剩余非关键词参数打包成元组,并传递给 *args 参数。
  4. 将剩余关键词参数打包成字典,并传递给 **kargs 参数。

对于默认参数,如果已经通过位置参数覆盖,那么就不能再次通过关键词参数传值,例如如下示例。

def foobar(a, b=2, *args, **kargs):
        print(a, b, args, kargs)
#foobar(1, 3, 5, 7, b=9) # FAIL
foobar(1)               # (1, 2, (), {})
foobar(1, 3)            # (1, 3, (), {})
foobar(1, 3, 5)         # (1, 3, (5,), {})
foobar(1, 3, 5, 7)      # (1, 3, (5, 7), {})
foobar(1, 3, 5, 7, c=9) # (1, 3, (5, 7), {'c': 9})

元组和字典可以展开,在传参的过程中非常好用,如下是一些常见的使用方法。

def foo(*args, **kargs):
        print(args, kargs)

data = ("hello", "world")
foo(data)   # ((('hello', 'world'),), {})
foo(*data)  # (('hello', 'world'), {})

data = {
        "hi": "hey",
        "bye": "byebye",
}
foo(data)   # (({'bye': 'byebye', 'hi': 'hey'},), {})
foo(*data)  # (('bye', 'hi'), {})
foo(**data) # ((), {'hi': 'hey', 'bye': 'byebye'})

对于元组,通过 * 符号可以展开 (也可以展开列表、字典 Key),然后传递到函数,在函数中的 args 变量会重新组合起来,就好像直接将元组传入一样;对于字典原理也基本类似,只是需要使用 ** 符号扩展。

还有如下一种场景。

def bar(a, b):
        print(a, b)
data = ("hello", "world")
bar(*data)  # ('hello', 'world')

data = {
        "a": "hello", 
        "b": "world"
}
bar(**data) # ('hello', 'world')

元组会按照顺序展开,而字典则需要确保 key 与参数的名称相同。

声明和传参的方式类似,但是需要保证其顺序;元组和字典可以很方便直接传参。


如果喜欢这里的文章,而且又不差钱的话,欢迎打赏个早餐 ^_^


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK