이 글의 내용은 주로 다음과 같은 주제와 방법을 다루고 있습니다. 글이 조금 길기 때문에 쉽게 참고하실 수 있도록 저장해 두시기 바랍니다.
함수 매개변수는 함수의 입력이며 다섯 가지 그룹으로 분류될 수 있습니다.
# 定义参数有默认值的函数,调用时其为可选型参数 def func(a, b=4, c=88): print(a, b, c) func(1) # prints: 1 4 88 func(b=5, a=7, c=9) # prints: 7 5 9 func(42, c=9) # prints: 42 4 9 func(42, 43, 44) # prints: 42, 43, 44
# 不定量位置参数 def minimum(*n): # print(type(n)) # n 是个元组 if n: # mn = n[0] for value in n[1:]: if value < mn: mn = value print(mn) minimum(1, 3, -7, 9) # n = (1, 3, -7, 9) - prints: -7 minimum() # n = () - prints: nothing
팁:
n이 비어 있는지 확인하기 위해 코드에서 간단한 if n:을 사용하는 방법을 보셨나요? 이는 Python에서 컬렉션 개체가 비어 있지 않으면 True로 평가되고 그렇지 않으면 False로 평가되기 때문입니다. 이는 튜플, 세트, 목록, 사전 등에 해당됩니다. 또 한 가지 주의할 점은 매개 변수 없이 함수를 호출할 때 조용히 아무 것도 하지 않는 대신 오류를 발생시키는 것이 좋을 수 있다는 것입니다. 이 경우 우리는 이 기능을 견고하게 만드는 데 관심을 두지 않고 오히려 가변 위치 매개변수를 이해합니다. 또한, 무한한 위치 매개변수를 정의하는 구문이 반복 가능한 압축 풀기 구문과 매우 유사하다는 사실을 알고 계셨나요? 결국 두 가지 특성은 서로 거울상입니다. 또한 무한한 위치 매개변수를 사용하면 압축을 푼 반복 가능 항목의 길이가 함수 정의의 매개변수 수와 일치하는지 여부에 대해 걱정할 필요가 없기 때문에 종종 함께 사용됩니다. 3. 가변 키워드 매개변수가변 키워드 매개변수는 가변 위치 매개변수와 매우 유사합니다. 유일한 차이점은 구문(* 대신 **)과 사전 형식으로 수집된다는 사실입니다:# 不定量关键字参数 def func(**kwargs): print(kwargs) func(a=1, b=42) # prints {'a': 1, 'b': 42} func() # prints {} func(a=1, b=46, c=99) # prints {'a': 1, 'b': 46, 'c': 99}
# 可变量关键字参数 def connect(**options): conn_params = { 'host': options.get('host', '127.0.0.1'), 'port': options.get('port', 5432), 'user': options.get('user', ''), 'pwd': options.get('pwd', ''), } print(conn_params) # 然后连接数据库(注释掉的代码行) # db.connect(**conn_params) connect() connect(host='127.0.0.42', port=5433) connect(port=5431, user='admin', pwd='super')
{'a': 1, 'b': 46, 'c': 99} {'host': '127.0.0.1', 'port': 5432, 'user': '', 'pwd': ''} {'host': '127.0.0.42', 'port': 5433, 'user': '', 'pwd': ''} {'host': '127.0.0.1', 'port': 5431, 'user': 'admin', 'pwd': 'super'}
从Python 3.8开始,PEP 570 (https://www.python.org/dev/peps/pep-0570/)引入了仅限位置的参数。有一种新的函数参数语法,/,表示一组函数形参必须在位置上指定,不能作为关键字参数传递。让我们看一个简单的例子:
# 仅限位置参数 def func(a, b, /, c): print(a, b, c) func(1, 2, 3) # prints: 1 2 3 func(1, 2, c=3) # prints 1 2 3
在上面的例子中,我们定义了一个函数func(),它指定了三个参数:a、b和c。函数签名中的/表示a和b必须按位置传递,也就是说,不能通过关键字传递。
示例中的最后两行显示,我们可以按位置传递所有三个参数来调用函数,或者可以按关键字传递c。这两种情况都可以正常工作,因为c定义在函数签名中的/之后。如果我们试图通过通过关键字传递a或b来调用函数,像这样:
func(1, b=2, c=3)
这将产生如下类似回溯跟踪信息:
Traceback (most recent call last): File "……", line 9, in <module> func(1, b=2, c=3) TypeError: func() got some positional-only arguments passed as keyword arguments: 'b'
前面的例子告诉我们,Python现在反馈给我们调用func()的方式,其意思是:通过关键字传递了参数b,但不允许这样做。
仅限位置参数也可以是可选的,如下所示:
# 可选的仅限位置参数 def func(a, b=2, /): print(a, b) func(4, 5) # prints 4 5 func(3) # prints 3 2
通过一些从官方文档中借来的例子来看看这个特性给该语言带来了什么。一个优点是能够完全模拟现有C编码函数的行为:
def divmod(a, b, /): "模拟内建函数 divmod()" return (a // b, a % b)
另一个重要的用例是在形参名没有啥有意义的帮助的情况下排除关键字实参:
len(obj='hello')
在上面的例子中,obj关键字参数降低了可读性。此外,如果我们希望重构len函数的内部结构,并将obj重命名为the_object(或任何其他名称),更改保证不会破坏任何客户端代码,因为不会有任何对len()函数的调用,会涉及到现在已经过时的obj参数名称。
最后,使用仅限位置形参意味着/左边的任何值都可以在不定量关键字实参中使用,如下例所示:
def func_name(name, /, **kwargs): print(name) print(kwargs) func_name('Positional-only name', name='Name in **kwargs') # 打印输出为: # Positional-only name # {'name': 'Name in **kwargs'}
在函数签名中保留参数名以便在**kwargs中使用的能力可以生成更简单、更清晰的代码。
现在来研究一下仅限位置类似版:仅限关键字参数。
Python 3引入了仅限关键字的参数。我们只简要地研究它们,因为它们的用例并不常见。有两种方法可以指定它们,要么在不定量位置参数之后,要么在不定的*之后。来看两个例子。代码如下:
# 仅限关键字参数 def kwo(*a, c): print(a, c) kwo(1, 2, 3, c=7) # prints: (1, 2, 3) 7 kwo(c=4) # prints: () 4 # kwo(1, 2) # 此行出问题——无效于法,并有如下错误 # TypeError: kwo() missing 1 required keyword-only argument: 'c' def kwo2(a, b=42, *, c): print(a, b, c) kwo2(3, b=7, c=99) # prints: 3 7 99 kwo2(3, c=13) # prints: 3 42 13 # kwo2(3, 23) # 此行出问题——无效于法,并有如下错误 # TypeError: kwo2() missing 1 required keyword-only argument: 'c'
正如预期的那样,函数kwo()接受数量可变的位置参数(a)和一个只有关键字的关键字c。调用的结果很简单,你可以取消对第三个调用的注释,以查看Python返回什么错误。
同样的情况也适用于函数kwo2(),它与kwo的不同之处在于,它接受一个位置参数a、一个关键字参数b和一个只有关键字的参数c。你可以取消对第三个调用的注释,以查看产生的错误。
现在应已知道了如何指定不同类型的输入参数,接下来看看如何在函数定义中组合它们。
可以在同一个函数中组合不同的参数类型(事实上,这样做通常非常有用)。就像在同一个函数调用中组合不同类型的实参一样,在顺序上有一些限制:
对于仅限位置参数和普通参数,任何必需的参数必须在任何可选参数之前定义。这意味着,如果你有一个可选的仅限位置参数,那么所有常规参数也必须是可选的。该规则不影响仅限关键字的参数。
如果没有例子,这些规则可能会有点难以理解,所以来看几个示例:
# 定义个带有所有参数形式的函数 def func(a, b, c=7, *args, **kwargs): print('a, b, c:', a, b, c) print('args:', args) print('kwargs:', kwargs) func(1, 2, 3, 5, 7, 9, A='a', B='b')
注意函数定义中参数的顺序。执行该程序会得到以下结果:
a, b, c: 1 2 3 args: (5, 7, 9) kwargs: {'A': 'a', 'B': 'b'}
现在再来看一个只有关键字参数的例子:
# 仅限观自在参数 def allparams(a, /, b, c=42, *args, d=256, e, **kwargs): print('a, b, c:', a, b, c) print('d, e:', d, e) print('args:', args) print('kwargs:', kwargs) allparams(1, 2, 3, 4, 5, 6, e=7, f=9, g=10)
注意,在函数声明中有仅限位置形参和仅限关键字形参:a仅限位置形参,而d和e仅限关键字形参。他们是在*args可变量位置参数之后,如果它们紧跟在单个*的后面,也会是一样的(在这种情况下,将没有任何可变位置参数)。运行程序会得到以下结果:
a, b, c: 1 2 3 d, e: 256 7 args: (4, 5, 6) kwargs: {'f': 9, 'g': 10}
另一件需要注意的事情是我们为可变量位置参数和关键字参数命名。你可以自由选择不同的名称,但请注意,args和kwargs是这些参数的常规名称,至少在一般情况下是这样。
为了简要回顾一下使用仅限位置和关键字说明符的函数签名,下面是一些进一步的示例。省略不定量位置和关键字参数,为简洁起见,我们只剩下以下语法:
def xxxFuncName(positional_only_parameters, /, positional_or_keyword_parameters, *, keyword_only_parameters): # 函数体 pass
首先,我们有仅限位置的参数,然后是位置或关键字参数,最后是仅限关键字参数。
其他一些有效签名如下:
def xxxFuncName(p1, p2, /, p_or_kw, *, kw): def xxxFuncName(p1, p2=None, /, p_or_kw=None, *, kw): def xxxFuncName(p1, p2=None, /, *, kw): def xxxFuncName(p1, p2=None, /): def xxxFuncName(p1, p2, /, p_or_kw): def xxxFuncName(p1, p2, /):
以上均为有效签名,下列为无效签名:
def xxxFuncName(p1, p2=None, /, p_or_kw, *, kw): def xxxFuncName(p1=None, p2, /, p_or_kw=None, *, kw): def xxxFuncName(p1=None, p2, /):
你可以在官方文档中阅读语法规范:
https://docs.python.org/3/reference/compound_stmts.html#functiondefinitions
提示:在这一点上,要很好的理解与掌握,一个有用的练习方法是实现上述示例签名中的任何一个,打印出这些参数的值,就像我们在前面的练习中所做的那样,并以不同的方式传递参数。
要注意的一件事是,在Python中,默认值是在定义时创建的;因此,根据默认值的可变性,对同一函数的后续调用可能会有不同的行为。让我们看一个例子:
# 带有可变默认值参数函数 def func(a=[], b={}): print(a) print(b) print('#' * 12) a.append(len(a)) # 影响a的默认值 b[len(a)] = len(a) # 影响b的默认值 func() func() func()
两个参数都有可变的默认值。这意味着,如果执行中影响了这些对象,任何修改都将停留在后续的函数调用中。看看你是否能理解这些调用的输出:
[] {} ############ [0] {1: 1} ############ [0, 1] {1: 1, 2: 2} ############
是不是很搞事?虽然这种行为一开始看起来很奇怪,但它实际上是有意义的,而且非常方便——例如,当使用“记忆”技术时,就有了天生之才的傲娇。更有趣的是,在调用之间,我们引入了一个不使用默认值的函数,比如:
# 中间调停者调用 func() func(a=[1, 2, 3], b={'B': 1}) func()
运行代码输出内容如下所示:
[] {} ############ [1, 2, 3] {'B': 1} ############ [0] {1: 1} ############
这个输出告诉我们,即使使用其他值调用函数,默认值也会被保留。我想到的一个问题是,如何每次都获得一个新的空值?惯例是这样的:
# 无陷阱可变缺省默认值 def func(a=None): if a is None: a = [] # 干些使用a的工作 ...
注意,通过使用前面的技术,如果调用函数时没有传递a,我们总是得到一个全新的空列表。
本文详细介绍了函数的输入参数分类、示例和调用,都是围绕如下主题展开:
位置或关键字参数:同时允许位置和关键字参数;
可变位置参数:在元组中收集任意数量的位置参数;
可变关键字参数:在字典中收集任意数量的关键字参数;
仅限位置参数:只能作为位置参数传递;
•仅限关键字参数:只能作为关键字参数传递。
위 내용은 Python 프로그래밍: 함수 입력 매개변수를 정의하는 것이 쉬운가요? 이 규칙을 마스터하셨나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!