Python函数的参数那些事

The terms parameter and argument can be used for the same thing: information that are passed into a function. From a function’s perspective: A parameter is the variable listed inside the parentheses in the function definition. An argument is the value that are sent to the function when it is called

以上是W3Schools对函数参数的定义,在定义中,将parameter和argument略加区分,即将函数定义时,括号内的参数称为parameter,而将函数调用时,传递给函数的参数称为argument,两者差别不大,但使用我们使用Google等英文工具时,加以区分可以一定程度上得到我们想要的答案。

Python是一种极其灵活的高级编程语言,当定义和使用函数时,合理地利用不同类型的参数是提高代码稳定性、灵活性的、可读性等的途径之一。
Python的参数类型多样,主要分为以下几种:

位置参数

位置参数是Python中最基础的参数类型,顾名思义,当调用函数并传入参数时,形参和实参的对应是依据位置(先后)判断的。如下所示,参数对应与传入顺序有关。

def person(name,age):
    print("name={name},age={age}".format(name=name,age=age))

person('Will',27) # name=Will,age=27
person(27,'Will') # name=27,age=Will
默认参数

默认参数,即在函数定义时,赋予参数默认值,该类型参数能够很好的应对某些场景,例如,调用函数时传入某一参数的值只有少部分情况会发生改变,这时,只使用位置参数代码会变得冗余;此外,有时由于调用函数需要对函数功能做出更改或进行某些细节上的改善需要添加参数,但又希望不对现有代码造成影响。

以上述例子为基础,如果在代码的编写过程中需要为person函数添加新的功能(输出人的所在城市),此时,当只使用位置参数时的解决方案如下:

def person(name,age,city):
    print("name={name},age={age},city={city}".format(name=name,age=age,city=city))

person('Will',27,'Beijing') # name=Will,age=27,city=Beijing
person('Will',27) # TypeError: person() missing 1 required positional argument: 'city'

这种方案可行,但是可以发现,采用这种方案的话,需要修改之前每一次调用函数person时所涉及的代码,会给代码的升级改善带来极大的不便,极易引进新的问题。此外,如果调用函数时,人的所在城市主要为Beijing,只有极少情况为其他时,在每次调用函数时都将Beijing传入略显冗余,当参数很多时,可读性显著下降。所以考虑使用默认参数:

def person(name,age,city="Beijing"):
    print("name={name},age={age},city={city}".format(name=name,age=age,city=city))

person('Will',27) # name=Will,age=27,city=Beijing
person('Will',27,"Shanghai") # name=Will,age=27,city=Shanghai
person('Will',27,city="Shanghai") # name=Will,age=27,city=Shanghai

从上述例子可以清晰地看出使用默认参数可以降低函数调用的难度,提高函数调用的灵活性。

有多个默认参数时,调用的时候,既可以按顺序提供默认参数,也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。

但是使用默认参数时,有一点需要额外注意
!!!默认参数必须指向不变对象!

def append(number, number_list=[]):
    number_list.append(number)
    print(number_list)
    return number_list

append(5) # expecting: [5], actual: [5]
append(7) # expecting: [7], actual: [5, 7]
append(2) # expecting: [2], actual: [5, 7, 2]

将可变列表或字典作为默认参数传递给函数会产生无法预料的后果。 通常,当程序员使用列表或字典作为函数的默认参数时,程序员希望程序在每次调用该函数时创建一个新的列表或字典。 但是,这不是Python要做的。 第一次调用该函数时,Python为列表或字典创建一个持久对象。 以后每次调用该函数时,Python都会使用与第一次调用该函数相同的持久对象。图例

一个很好的解决方案如下:

# the keyword None is the sentinel value(https://en.wikipedia.org/wiki/Sentinel_value) representing empty list
def append(number, number_list=None):
    if number_list is None:
        number_list = []
    number_list.append(number)
    print(number_list)
    return number_list

append(5) # expecting: [5], actual: [5]
append(7) # expecting: [7], actual: [7]
append(2) # expecting: [2], actual: [2]
可变参数

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
理论上讲大部分需要传入不定量参数的场景都可以通过list或tuple解决,但是灵活性不高,需要提前组装,例如,

def factorial(iter):
    ret = 1
    for i in iter:
        ret = ret * i
    print(ret)

factorial((1,2,3,4,5,6,7,8)) # 40320

如果利用可变参数,调用函数的方式可以简化成这样:

def factorial(*args):
    ret = 1
    for i in args:
        ret = ret * i
    print(ret)

factorial(1,2,3,4,5,6,7,8) # 40320

当已经有一个list或者tuple,要调用一个可变参数也可以利用*,

li=[1,2,3,4,5,6,7,8] # list
factorial(*li) # 40320

有关*的详细介绍可以阅读Python系列的其他文章-优雅的使用*

关键字参数

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

def people(name, age, **kwargs):
    print("name={name},age={age},kwargs={kwargs}".format(name=name,age=age,kwargs=kwargs))

people("Will",27,gender='female',city="Beijing") # name=Will,age=27,kwargs={'gender': 'female', 'city': 'Beijing'}

关键字参数可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。

此外,当已经有一个dict,要调用一个关键字参数也可以利用**

kwargs = {'gender': 'female', 'city': 'Beijing'}
people("Will",27,**kwargs) # name=Will,age=27,kwargs={'gender': 'female', 'city': 'Beijing'}
命名关键字参数(keyword-only argument)

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kwargs检查,并且函数调用者在调用函数时传入任意参数。

def people(name, age, **kwargs):
    needPrint=kwargs.setdefault('needPrint',False)
    if needPrint:
        print("name={name},age={age},kwargs={kwargs}".format(name=name,age=age,kwargs=kwargs))
    else:
        print("needPrint is False")
        
people("Will",27,gender='female',needPrint=True) # name=Will,age=27,kwargs={'gender': 'female', 'needPrint': True}
people("Will",27,gender='female',needPrint=False)# needPrint is False
people("Will",27,gender='female') # needPrint is False

如果要限制关键字参数的名字,就可以用命名关键字参数,即使用特殊分隔符*,*后面的参数被视为命名关键字参数,如下所示,gender和city都为命名关键字参数

def people(name, age, *, gender, city):
    print("name={name},age={age},gender={gender},city={city}".format(name=name,age=age,gender=gender,city=city))

命名关键字参数必须传入参数名,如果没有传入参数名,默认作为位置参数处理,所以调用将报错:

def people(name, age, *, gender, city):
    print("name={name},age={age},gender={gender},city={city}".format(name=name,age=age,gender=gender,city=city))

people("Will",27,"female","Beijing") # TypeError: people() takes 2 positional arguments but 4 were given

命名关键字参数同样也可以有默认值,使用默认值的命名关键字参数可以不用传入值。

参数组合

参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

1.廖雪峰的官方网站
2.Python Anti-Patterns

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值