[Python] Python函数传参机制

 美图欣赏2022/07/20

引言

Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数

# 1.无返回值、参数的函数
def fn1():
    print('Hello World!')
fn1() # Hello World!

# 2.带返回值、无参数的函数
def fn2():
    data = 'Hello World!'
    return data
fn2() # 'Hello World!'

# 3.带一个参数(无默认值)的函数
def fn3(data):
    res = 'Hello ' + data
    return res
fn3('World!') # 'Hello World!'

# 4.带有多个参数(无默认值)的函数
def fn4(name, age):
    res = '我叫' + name + ',今年' + str(age) + '岁'
    return res
fn4('Andy',18) # '我叫Andy,今年18岁'
# 注意:一定要按照原来形参的顺序传递
fn4('20','Harry') # '我是20,今年Harry岁'
fn4(name='Tom',age=20) # '我叫Tom,今年20岁'
fn4(age=20,name='Tom') # '我叫Tom,今年20岁'
fn4('Tom',age=20) # '我叫Tom,今年20岁'
# 注意:在调用的时候还是要按照原函数中的顺序,否则会报错
fn4(age=20,'Tom') # 报错

# 5.参数设置默认值(一个参数)的函数
def fn5(name='Lee'):
    res = 'Hello ' + name
    return res
fn5() # 'Hello Lee'
fn5('Andy') # 'Hello Andy'
fn5(name='Andy') # 'Hello Andy'

# 6.参数设置默认值(多个参数)的函数
def fn6(name='Jack', age=20):
    res = '我叫' + name + ',今年' + str(age) + '岁'
    return res
fn6() # '我叫Jack,今年20岁'
fn6(name='Harry') # '我叫Harry,今年20岁'
fn6(age=22) # '我叫Jack,今年22岁'
fn6(name='Rita',age=25) # '我叫Rita,今年25岁'

# 7.部分参数使用默认值的函数
def fn7(name, age=20):
    res = '我叫' + name + ',今年' + str(age) + '岁'
    return res
fn7('Rita') # '我叫Rita,今年20岁'
fn7(name='Rita') # '我叫Rita,今年20岁'
fn7('Rita',23) # '我叫Rita,今年23岁'
fn7('Rita',age=23) # '我叫Rita,今年23岁'
fn7(age=23,'Rita') # 报错
fn7(age=23,name='Rita') # '我叫Rita,今年23岁'

# 8.带有*args参数的函数
def fn8(*args):
    data = args
    return data
fn8() # ()
fn8(178) # (178,)
fn8(178,185) # (178, 185)

def height(*args):
    # 对args中的元素进行循环操作
    for data in args:
        print("身高是:{}m".format(data / 100))
'''
身高是:1.71m
身高是:1.85m
'''
height(171,185)

# 9.带有**kwargs参数的函数
def fn9(**kwargs):
    data = kwargs
    print(data)
fn9() # {}
fn9(name='Andy') # {'name': 'Andy'}
fn9(name='Harry',age=24) # {'name': 'Harry', 'age': 24}

def information(**kwargs):
    for key,val in kwargs.items():
        print("{0} = {1}".format(key,val))
information(name='Andy') # name = Andy
'''
name = Vanly
age = 18
height = 170
'''
information(name='Vanly', age=18, height=170)

# 10.带有形参和*args参数的函数
def fn10(x, *args):
    print("x:",x)
    print("args:",args)
'''
x: 1
args: ()
'''
fn10(1)
'''
x: 1
args: (2,)
'''
fn10(1,2)
'''
x: 1
args: ()
'''
fn10(1,2,3,4)
'''
x: 1
args: (2, 3, 4, 'Andy')
'''
fn10(1,2,3,4,'Andy')

# 11.带有形参和**kwargs参数的函数
def fn11(x, **kwargs):
    print("x:",x)
    print("kwargs:",kwargs)
'''
x: 1
kwargs: {}
'''
fn11(1)
'''
x: 1
kwargs: {'name': 'Andy'}
'''
fn11(1,name='Andy')
'''
x: 1
kwargs: {'name': 'Andy', 'age': 18}
'''
fn11(1,name='Andy',age=18)

# 12.带有形参 + *args参数 + **kwargs参数的函数
def fn12(x, *args, **kwargs):
    print("x:",x)
    print("args:",args)
    print("kwargs:",kwargs)
'''
x: 1
args: ()
kwargs: {}
'''
fn12(1)
'''
x: 1
args: (2, 3)
kwargs: {}
'''
fn12(1,2,3)
'''
x: 1
args: ()
kwargs: {'name': 'Andy', 'age': 18}
'''
fn12(1,name='Andy',age=18)
'''
x: 1
args: (2, 3)
kwargs: {'name': 'Andy', 'age': 18}
'''
fn12(1,2,3,name='Andy',age=18)
'''
x: 1
args: (2, 3)
kwargs: {'name': 'Andy', 'age': 18}
'''
kwargs = {'name':'Andy', 'age':18}
fn12(1,2,3,**kwargs)

1.位置参数

编写一个计算x^{2}的函数

def power(x):
    return x * x

对于power(x)函数,参数x就是一个位置参数 

当我们调用power(x)函数时,必须传入有且仅有的一个参数x

power(5) # 25
power(10) # 100

 编写一个计算x^{n}的函数

def power(x, n):
    res = 1
    while n > 0:
        n = n - 1
        res = res * x
    return res

对于这个修改后的power(x,n)函数,可以计算任意n次方 

修改后的power(x,n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n

# 5的3次方
power(5,3) # 125
# 10的4次方
power(10,4) # 10000

2.默认参数 

def power(x, n):
    res = 1
    while n > 0:
        n = n - 1
        res = res * x
    return res

# TypeError: power() missing 1 required positional argument: 'n'
power(5)

Python的错误信息很明确: 调用函数power()缺少了一个位置参数n 

针对上述出现无法正常调用power(x,n)函数的情况,由于我们经常计算x^{2},所以完全可以把第二个参数n的默认值设定为2(设置默认参数)

# 默认参数可以简化函数的调用,降低调用函数的难度
def power(x, n=2):
    res = 1
    while n > 0:
        n = n - 1
        res = res * x
    return res

# 调用power(5)相当于调用power(5,2)
power(5) # 25
power(5,2) # 25

而对于n > 2的其他情况,就必须明确地传入n 

def power(x, n=2):
    res = 1
    while n > 0:
        n = n - 1
        res = res * x
    return res

# 5的3次方
power(5,3) # 125

设置默认参数注意点

1. 必选参数在前,默认参数在后,否则Python的解释器会报错

2.当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面,其中变化小的参数就可以作为默认参数

例如,编写一个大学新生注册信息登记的函数

def students(name, gender):
    print('姓名:', name)
    print('性别:', gender)

# 调用students()函数只需要传入两个参数
'''
姓名: Odin
性别: M
'''
students('Odin','M')

如果要继续传入年龄、省份等信息怎么办?这样会使得调用函数的复杂度大大增加

我们可以把年龄和省份设为默认参数

def students(name, gender, age=18, province='广东'):
    print('姓名:', name)
    print('性别:', gender)
    print('年龄:', age)
    print('省份:', province)

上述操作,可使大多数学生注册时不需要提供年龄和省份,只需提供必须的两个参数

'''
姓名: Harry
性别: M
年龄: 18
省份: 广东
'''
students('Harry','M')

只有与默认参数不符的学生才需要提供额外的信息

'''
姓名: Lee
性别: F
年龄: 19
省份: 广东
'''
students('Lee', 'F', 19)
'''
姓名: Summer
性别: F
年龄: 18
省份: 安徽
'''
students('Summer', 'F', province='安徽')

可见,默认参数降低了函数调用的难度

有多个默认参数时,调用的时候可以按顺序提供默认参数

# 调用students('Bob', 'M', 7),意思是,除了name,gender这两个参数外,最后1个参数应用在参数age上,
# province参数由于没有提供,仍然使用默认值
'''
姓名: Bob
性别: M
年龄: 20
省份: 广东
'''
students('Bob', 'M', 20)

也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上

'''
姓名: Ruby
性别: F
年龄: 18
省份: 湖南
'''
students('Ruby', 'F', province='湖南')

注意: 定义默认参数要牢记一点,默认参数必须指向不变对象

定义一个函数add_res,传入一个list,添加一个H再返回结果

def add_res(res=[]):
    res.append('H')
    return res
# 正常调用不会出错
add_res([1, 2, 3]) # [1, 2, 3, 'H']
add_res(['x','y','z']) # ['x', 'y', 'z', 'H']

# 第一次使用默认参数调用不出错
add_res() # ['H']
# 再次调用add_res()出错
add_res() # ['H', 'H']
add_res() # ['H', 'H', 'H']

Python函数在定义的时候,默认参数res的值就被计算出来了,即[],因为默认参数res也是一个变量,它指向对象[],每次调用该函数,如果改变了res的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]

默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

解决上述问题代码如下所示:

def add_res(res=None):
    if res is None:
        res = []
    res.append('H')
    return res

add_res() # ['H']
add_res() # ['H']
add_res() # ['H']

3.可变参数(*args)

可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个参数

问题: 给定一组数字a,b,c……,请计算a^{2} + b^{2} + c^{2} + ...

def calc(*args):
    sum = 0
    for n in args:
        sum = sum + n * n
    return sum

定义可变参数在参数前面加了一个 *号 

调用calc函数时,可以传入任意个参数,包括0个参数

calc() # 0
calc(1,2,3) # 14
calc(1,3,5,7) # 84

调用函数时,可变参数既可以直接传入,又可以先组装成列表list或元组tuple,再通过*args传入 

# *nums表示把nums这个list的所有元素作为可变参数传进去
nums = [1, 2, 3]
calc(*nums) # 14

可变参数允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple元组

注意:

*args是可变参数,args接收的是一个元组tuple

使用*args是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法

4.关键字参数(**kwargs)

关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict字典

关键字参数可以扩展函数的功能

def person(name, age, **kwargs):
    print('name:', name, 'age:', age, 'info:', kwargs)

函数person除了必选参数name和age外,还接受关键字参数kwargs 

# name: Andy age: 25 info: {}
person('Andy', 25)
# name: Lee age: 26 info: {'city': 'GuangZhou'}
person('Lee', 26, city='GuangZhou')
# name: Rita age: 30 info: {'gender': 'M', 'job': 'Engineer'}
person('Rita', 30, gender='M', job='Engineer')

调用函数时,关键字参数既可以直接传入,又可以先组装成dict字典,再通过**kwargs传入 

'''
**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kwargs参数
kwargs将获得一个dict,注意kwargs获得的dict是extra的一份拷贝,对kwargs的改动不会影响到函数外的extra
'''
# name: Harry age: 24 info: {'city': 'DaLian', 'job': 'Engineer'}
extra = {'city': 'DaLian', 'job': 'Engineer'}
person('Harry', 24, **extra)

注意

**kwargs是关键字参数,kwargs接收的是一个字典dict  

使用**kwargs是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值