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)
编写一个计算的函数
- def power(x):
- return x * x
对于power(x)函数,参数x就是一个位置参数
当我们调用power(x)函数时,必须传入有且仅有的一个参数x
- power(5) # 25
- power(10) # 100
编写一个计算的函数
- 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
- 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)函数的情况,由于我们经常计算,所以完全可以把第二个参数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']
可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个参数
问题: 给定一组数字a,b,c……,请计算
- 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的习惯写法,当然也可以用其他参数名,但最好使用习惯用法
关键字参数允许传入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的习惯写法,当然也可以用其他参数名,但最好使用习惯用法