超详细!少数人才知道的 Python 函数定义详解

2025 篇文章 2 订阅
1891 篇文章 13 订阅

Python 函数定义时支持可变数量的参数。

一、默认值参数

在 Python 中给函数的参数指定默认值是一种十分常见的使用方式,这样在调用函数时,可以使用比定义时更少的参数。

示例代码

def chat_request(response, retries=4, reminder='Please try again!'):
    while True:
        response = input(response)
        if response in ('y', 'yes'):
            return True
        if response in ('n', 'no'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)

示例代码中定义的函数chat_request可以使用以下三种调用方式:

只给出必选实参response

chat_request('hello world!')

给出一个可选实参retries

chat_request('please say no or yes', 2)

给出所有实参response, retries, reminder

chat_request('please input your mind', 2, 'Dear Baby, but only yes or no!')

默认值在 定义 作用域里的函数定义中求值,为理解这句话的含义,请看如下示例。

Input:

name = 'tony'

def get_name(arg=name):
    print(arg)

name = 'lily'
get_name()

Output:

tony

PS:  默认值只计算一次,默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。

例如,下面的get_num函数会累积后续调用时传递的参数,可以发现输出结果与预期不一致。

Input:

def get_num(num, list1=[]):
    list1.append(num)
    return list1

print(get_num(100))
print(get_num(200))
print(get_num(300))

Output:

[100]
[100, 200]
[100, 200, 300]

PS:  如果不想在后续调用之间共享默认值时,可采取以下方式改写get_num函数

Input:

def get_num(num, list1=None):
    if list1 is None:
        list1 = []
    list1.append(num)
    return list1
    
print(get_num(100))
print(get_num(200))
print(get_num(300))

Output:

[100]
[200]
[300]

二、关键字参数

在 Python 中也可以使用kwarg=value形式的关键字参数来调用函数。

示例代码

def animal(name, state='active', action='fly', type='land'):
    print("This animal wouldn't", action, end=' ')
    print("if you reminder", name, "you are great.")
    print("-- general animal, the", type)
    print("-- They're", state, "!")

代码参数说明

animal函数接受一个必选参数(name)和三个可选参数(state, action 和 type)。

该函数有以下几种调用方式。

animal('jingmao')                                   # 1 positional argument
animal(name='keji')                                 # 1 keyword argument
animal(name='chaiquan', action='running')           # 2 keyword arguments
animal(action='sleep', name='pig')                  # 2 keyword arguments
animal('cat', 'smile', 'jump')                      # 3 positional arguments
animal('bird', state='inactive')                    # 1 positional, 1 keyword

以下都是无效的调用方式。

animal()                       # required argument missing
animal(name='rabbit', 'dead')  # non-keyword argument after a keyword argument
animal('fox', name='bird')     # duplicate value for the same argument
animal(profile='warning')      # unknown keyword argument

函数调用时,关键字参数必须跟在位置参数后面。所有传递的关键字参数都必须匹配一个函数接受的参数。

例如,profile 不是函数 animal 的有效参数,关键字参数的顺序并不重要。这也包括必选参数

PS: 不能对同一个参数多次赋值。

下面的举例就是一个反例

def get_name(name):
    print(name)

get_name('dog', name='cat')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: get_name() got multiple values for argument 'name'

在 Python 中形参还可以是 **name 形式,指接收一个字典(kwarg=value),该字典包含与函数中已定义形参对应之外的所有关键字参数。

**name 形参可以与 *name(指接收一个元组,该元组包含形参列表之外的位置参数)形参组合使用,请注意:*name 必须在 **name 前面

示例代码

Input:

def animalShop(animal_name, *arguments, **keywords):
    print("-- Do you have any", animal_name, "?")
    print("-- I'm sorry, we're all out of", animal_name)
    for argument in arguments:
        print(argument)
    print("*" * 40)
    for keyword in keywords:
        print(keyword, ":", keywords[keyword])

animalShop函数可以使用如下方式调用

animalShop("dog", "It's very Cute, sir.",
           "It's really very, VERY Smart, sir.",
           shopkeeper="tony",
           client="Online Shop",
           market="Chat Connect")

Output:

-- Do you have any dog ?
-- I'm sorry, we're all out of dog
It's very Cute, sir.
It's really very, VERY Smart, sir.
****************************************
shopkeeper : tony
client : Online Shop
market : Chat Connect

PS: 注意,关键字参数在输出结果中的顺序与调用函数时的顺序一致。

三、特殊参数

在 Python 函数中,默认情况下,参数可以按位置显式关键字传递。

但为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置按位置或关键字,还是仅按关键字传递。

函数定义如下:

def function(position_arg1, position_arg2, /, position_or_keyword, *, kwd1, kwd2):
   pass

function函数定义中:

  • position_arg1position_arg2仅仅只是位置参数

  • position_or_keyword可以是位置参数也可以是关键字参数

  • kwd1kwd2仅仅只是关键字参数

PS: /*是可选的,这些符号表明形参如何把参数值传递给函数:位置、位置或关键字、关键字。关键字形参也叫作命名形参。

3.1 位置或关键字参数

函数定义中未使用 / 和 * 时,参数可以按位置或关键字传递给函数。

3.2 仅位置参数

细节补充一下,特定形参可以标记为 仅限位置

  • 仅限位置时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在 / (正斜杠)前。

  • / 用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有 /,则表示没有仅限位置形参。

  • / 后可以是 位置或关键字 或 仅限关键字 形参。

3.3 仅限关键字参数

细节补充一下,把形参标记为 仅限关键字,表明必须以关键字参数形式传递该形参,应在参数列表中第一个 仅限关键字 形参前添加 *

示例代码

如下函数定义示例,注意 / 和 * 标记。

def standard_arg(arg):
    print(arg)

def pos_only_arg(arg, /):
    print(arg)

def kwd_only_arg(*, arg):
    print(arg)

def union_example(pos_only, /, standard, *, kwd_only):
    print(pos_only, standard, kwd_only)

第一个函数定义 standard_arg 是最常见的形式,对调用方式没有任何限制,可以按位置也可以按关键字传递参数

# 按位置传递参数
standard_arg(200)
200
# 按关键字传递参数
standard_arg(arg=200)
200

第二个函数 pos_only_arg 的函数定义中有 /,仅限使用位置形参

# 按位置传递参数正常,无报错
pos_only_arg(100)
100

# 按关键字传递参数异常,会抛异常
pos_only_arg(arg=100)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'

第三个函数 kwd_only_args 的函数定义通过 * 表明仅限关键字参数

# 按位置传递参数异常,会抛异常
kwd_only_arg(300)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given

# 按关键字传递参数正常,无报错
kwd_only_arg(arg=300)
3

最后一个函数 union_example 在同一个函数定义中,使用了全部三种调用方式

# 第3个参数仅为关键字参数,这里使用位置参数传参,会报错
union_example(100, 200, 300)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: union_example() takes 2 positional arguments but 3 were given

# 第2个参数使用位置参数传参,无报错
union_example(100, 200, kwd_only=300)
输出:100 200 300

# 第2个参数使用关键字参数传参,无报错
union_example(100, standard=200, kwd_only=300)
输出:100 200 300

# 第1个参数仅为位置参数,这里使用关键字参数传参,会报错
union_example(pos_only=100, standard=200, kwd_only=300)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: union_example() got some positional-only arguments passed as keyword arguments: 'pos_only'

位置参数与关键字参数key名称冲突

在 key_error 函数定义中,kwargs 把 name 当作键,可能与位置参数 name 产生潜在冲突

Input:

def key_error(name, **kwargs):
    return 'name' in kwargs

Output:

key_error('tony', **{'name': 'lucy'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: key_error() got multiple values for argument 'name'

冲突解决方法

在位置参数 name 后加上 / (仅限位置参数)就可以了。

此时,函数定义把 name 当作位置参数,'name' 也可以作为关键字参数的键了。

即:仅限位置形参的名称可以在 **kwargs 中使用,不会产生冲突。

def key_error(name, **kwargs):
    return 'name' in kwargs

key_error('tony', **{'name': 'lucy'})
True

四、任意实参列表

在 Python 函数调用过程中使用任意数量的实参是不常见的,通常这些实参包含在元组中。

在可变数量的实参之前,可能有若干个普通参数,如下示例代码。

def person(p_file, separator, *args):
    p_file.write(separator.join(args))

*args 形参后的任何形式参数只能是仅限关键字参数,即只能用作关键字参数,不能用作位置参数,如下示例代码。

def test_concat(*args, sep="/"):
    return sep.join(args)

test_concat("name", "sex", "age")
'name/sex/age'
test_concat("name", "sex", "age", sep=".")
'name.sex.age'

五、解包实参列表

在 Python 中函数调用需要独立的位置参数,如果是可变数量的位置参数,它的实参在列表或元组里时,要执行相反的操作。

例如,常用的内置 range() 函数要求传递独立的 start 和 stop 实参。

如果这些参数不是独立的,则要在调用函数时,用 * 操作符把实参从列表或元组解包出来。

示例代码

list(range(1, 4))            # normal call with separate arguments
输出:[1, 2, 3]

moreNumber_args = [1, 4]
list(range(*moreNumber_args)) # call with arguments unpacked from a list
输出:[1, 2, 3]

同理,字典可以用 ** 操作符传递关键字参数

def animal(name, state='active', action='fly'):
    print("This animal wouldn't", action, end=' ')
    print("if you reminder", name, "you are great.", end=' ')
    print("-- They're", state, "!")
 
d = {"name": "dog", "state": "active", "action": "run"}

animal(**d)
输出:This animal wouldn't run if you reminder dog you are great. -- They're active !

最后: 为了回馈铁杆粉丝们,我给大家整理了完整的软件测试视频学习教程,朋友们如果需要可以自行免费领取【保证100%免费】

在这里插入图片描述

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

面试文档获取方式:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值