• [Python] Python函数传参机制


     美图欣赏2022/07/20

    引言

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

    1. # 1.无返回值、参数的函数
    2. def fn1():
    3. print('Hello World!')
    4. fn1() # Hello World!
    5. # 2.带返回值、无参数的函数
    6. def fn2():
    7. data = 'Hello World!'
    8. return data
    9. fn2() # 'Hello World!'
    10. # 3.带一个参数(无默认值)的函数
    11. def fn3(data):
    12. res = 'Hello ' + data
    13. return res
    14. fn3('World!') # 'Hello World!'
    15. # 4.带有多个参数(无默认值)的函数
    16. def fn4(name, age):
    17. res = '我叫' + name + ',今年' + str(age) + '岁'
    18. return res
    19. fn4('Andy',18) # '我叫Andy,今年18岁'
    20. # 注意:一定要按照原来形参的顺序传递
    21. fn4('20','Harry') # '我是20,今年Harry岁'
    22. fn4(name='Tom',age=20) # '我叫Tom,今年20岁'
    23. fn4(age=20,name='Tom') # '我叫Tom,今年20岁'
    24. fn4('Tom',age=20) # '我叫Tom,今年20岁'
    25. # 注意:在调用的时候还是要按照原函数中的顺序,否则会报错
    26. fn4(age=20,'Tom') # 报错
    27. # 5.参数设置默认值(一个参数)的函数
    28. def fn5(name='Lee'):
    29. res = 'Hello ' + name
    30. return res
    31. fn5() # 'Hello Lee'
    32. fn5('Andy') # 'Hello Andy'
    33. fn5(name='Andy') # 'Hello Andy'
    34. # 6.参数设置默认值(多个参数)的函数
    35. def fn6(name='Jack', age=20):
    36. res = '我叫' + name + ',今年' + str(age) + '岁'
    37. return res
    38. fn6() # '我叫Jack,今年20岁'
    39. fn6(name='Harry') # '我叫Harry,今年20岁'
    40. fn6(age=22) # '我叫Jack,今年22岁'
    41. fn6(name='Rita',age=25) # '我叫Rita,今年25岁'
    42. # 7.部分参数使用默认值的函数
    43. def fn7(name, age=20):
    44. res = '我叫' + name + ',今年' + str(age) + '岁'
    45. return res
    46. fn7('Rita') # '我叫Rita,今年20岁'
    47. fn7(name='Rita') # '我叫Rita,今年20岁'
    48. fn7('Rita',23) # '我叫Rita,今年23岁'
    49. fn7('Rita',age=23) # '我叫Rita,今年23岁'
    50. fn7(age=23,'Rita') # 报错
    51. fn7(age=23,name='Rita') # '我叫Rita,今年23岁'
    52. # 8.带有*args参数的函数
    53. def fn8(*args):
    54. data = args
    55. return data
    56. fn8() # ()
    57. fn8(178) # (178,)
    58. fn8(178,185) # (178, 185)
    59. def height(*args):
    60. # 对args中的元素进行循环操作
    61. for data in args:
    62. print("身高是:{}m".format(data / 100))
    63. '''
    64. 身高是:1.71m
    65. 身高是:1.85m
    66. '''
    67. height(171,185)
    68. # 9.带有**kwargs参数的函数
    69. def fn9(**kwargs):
    70. data = kwargs
    71. print(data)
    72. fn9() # {}
    73. fn9(name='Andy') # {'name': 'Andy'}
    74. fn9(name='Harry',age=24) # {'name': 'Harry', 'age': 24}
    75. def information(**kwargs):
    76. for key,val in kwargs.items():
    77. print("{0} = {1}".format(key,val))
    78. information(name='Andy') # name = Andy
    79. '''
    80. name = Vanly
    81. age = 18
    82. height = 170
    83. '''
    84. information(name='Vanly', age=18, height=170)
    85. # 10.带有形参和*args参数的函数
    86. def fn10(x, *args):
    87. print("x:",x)
    88. print("args:",args)
    89. '''
    90. x: 1
    91. args: ()
    92. '''
    93. fn10(1)
    94. '''
    95. x: 1
    96. args: (2,)
    97. '''
    98. fn10(1,2)
    99. '''
    100. x: 1
    101. args: ()
    102. '''
    103. fn10(1,2,3,4)
    104. '''
    105. x: 1
    106. args: (2, 3, 4, 'Andy')
    107. '''
    108. fn10(1,2,3,4,'Andy')
    109. # 11.带有形参和**kwargs参数的函数
    110. def fn11(x, **kwargs):
    111. print("x:",x)
    112. print("kwargs:",kwargs)
    113. '''
    114. x: 1
    115. kwargs: {}
    116. '''
    117. fn11(1)
    118. '''
    119. x: 1
    120. kwargs: {'name': 'Andy'}
    121. '''
    122. fn11(1,name='Andy')
    123. '''
    124. x: 1
    125. kwargs: {'name': 'Andy', 'age': 18}
    126. '''
    127. fn11(1,name='Andy',age=18)
    128. # 12.带有形参 + *args参数 + **kwargs参数的函数
    129. def fn12(x, *args, **kwargs):
    130. print("x:",x)
    131. print("args:",args)
    132. print("kwargs:",kwargs)
    133. '''
    134. x: 1
    135. args: ()
    136. kwargs: {}
    137. '''
    138. fn12(1)
    139. '''
    140. x: 1
    141. args: (2, 3)
    142. kwargs: {}
    143. '''
    144. fn12(1,2,3)
    145. '''
    146. x: 1
    147. args: ()
    148. kwargs: {'name': 'Andy', 'age': 18}
    149. '''
    150. fn12(1,name='Andy',age=18)
    151. '''
    152. x: 1
    153. args: (2, 3)
    154. kwargs: {'name': 'Andy', 'age': 18}
    155. '''
    156. fn12(1,2,3,name='Andy',age=18)
    157. '''
    158. x: 1
    159. args: (2, 3)
    160. kwargs: {'name': 'Andy', 'age': 18}
    161. '''
    162. kwargs = {'name':'Andy', 'age':18}
    163. fn12(1,2,3,**kwargs)

    1.位置参数

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

    1. def power(x):
    2. return x * x

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

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

    1. power(5) # 25
    2. power(10) # 100

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

    1. def power(x, n):
    2. res = 1
    3. while n > 0:
    4. n = n - 1
    5. res = res * x
    6. return res

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

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

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

    2.默认参数 

    1. def power(x, n):
    2. res = 1
    3. while n > 0:
    4. n = n - 1
    5. res = res * x
    6. return res
    7. # TypeError: power() missing 1 required positional argument: 'n'
    8. power(5)

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

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

    1. # 默认参数可以简化函数的调用,降低调用函数的难度
    2. def power(x, n=2):
    3. res = 1
    4. while n > 0:
    5. n = n - 1
    6. res = res * x
    7. return res
    8. # 调用power(5)相当于调用power(5,2)
    9. power(5) # 25
    10. power(5,2) # 25

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

    1. def power(x, n=2):
    2. res = 1
    3. while n > 0:
    4. n = n - 1
    5. res = res * x
    6. return res
    7. # 5的3次方
    8. power(5,3) # 125

    设置默认参数注意点

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

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

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

    1. def students(name, gender):
    2. print('姓名:', name)
    3. print('性别:', gender)
    4. # 调用students()函数只需要传入两个参数
    5. '''
    6. 姓名: Odin
    7. 性别: M
    8. '''
    9. students('Odin','M')

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

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

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

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

    1. '''
    2. 姓名: Harry
    3. 性别: M
    4. 年龄: 18
    5. 省份: 广东
    6. '''
    7. students('Harry','M')

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

    1. '''
    2. 姓名: Lee
    3. 性别: F
    4. 年龄: 19
    5. 省份: 广东
    6. '''
    7. students('Lee', 'F', 19)
    8. '''
    9. 姓名: Summer
    10. 性别: F
    11. 年龄: 18
    12. 省份: 安徽
    13. '''
    14. students('Summer', 'F', province='安徽')

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

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

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

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

    1. '''
    2. 姓名: Ruby
    3. 性别: F
    4. 年龄: 18
    5. 省份: 湖南
    6. '''
    7. students('Ruby', 'F', province='湖南')

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

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

    1. def add_res(res=[]):
    2. res.append('H')
    3. return res
    1. # 正常调用不会出错
    2. add_res([1, 2, 3]) # [1, 2, 3, 'H']
    3. add_res(['x','y','z']) # ['x', 'y', 'z', 'H']
    4. # 第一次使用默认参数调用不出错
    5. add_res() # ['H']
    6. # 再次调用add_res()出错
    7. add_res() # ['H', 'H']
    8. add_res() # ['H', 'H', 'H']

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

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

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

    1. def add_res(res=None):
    2. if res is None:
    3. res = []
    4. res.append('H')
    5. return res
    6. add_res() # ['H']
    7. add_res() # ['H']
    8. add_res() # ['H']

    3.可变参数(*args)

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

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

    1. def calc(*args):
    2. sum = 0
    3. for n in args:
    4. sum = sum + n * n
    5. return sum

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

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

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

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

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

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

    注意:

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

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

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

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

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

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

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

    1. # name: Andy age: 25 info: {}
    2. person('Andy', 25)
    3. # name: Lee age: 26 info: {'city': 'GuangZhou'}
    4. person('Lee', 26, city='GuangZhou')
    5. # name: Rita age: 30 info: {'gender': 'M', 'job': 'Engineer'}
    6. person('Rita', 30, gender='M', job='Engineer')

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

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

    注意

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

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

  • 相关阅读:
    被遗忘的艺术:图的思维方式
    【324. 摆动排序 II】
    今年这情况。。真有点想读研了
    07-服务管理-03-自建yum仓库(手把手教你搭建内网yum源)
    Web 前端 || 和 &&运算符判定规则和常用法
    AI读懂中国,文心方可雕龙
    Antdv+Asp.net WebApi开发学生信息管理系统(一)
    Java,输出一个10行的杨辉三角
    【股票价格走势预测】数据挖掘实验一
    为什么从 MVC 到 DDD,架构的本质是什么?
  • 原文地址:https://blog.csdn.net/Hudas/article/details/125853944