- images
- results
- .gitignore
- 1.1概论.ipynb
- 1.2 环境配置.pdf
- 1.3数据类型.ipynb
- 1.4 人机交互.ipynb
- 1.5 对象与变量.ipynb
- 1.6 编码与命名规范.ipynb
- 2.1 数值类型.ipynb
- 2.2 数值类型转换.ipynb
- 2.3 数值元算.ipynb
- 2.4常用数学运算函数.ipynb
- 2.5 math 模块及其应用.ipynb
- 2.6.1 逻辑值测试.ipynb
- 2.6.2 成员运算.ipynb
- 2.6.3 比较运算.ipynb
- 2.6.4 布尔运算.ipynb
- 2.6.5 运算优先级.ipynb
- 2.ipynb
- 3.1 流程控制结构.ipynb
- 3.3.1 for 循环语句.ipynb
- 3.3.3 rang.ipynb
- 3.3.3 while 循环语句.ipynb
- 3.4 and 3.5 分支结构和条件.ipynb
- 3.6 and 3.7 .ipynb
- 3.9 异常处理.ipynb
- 4 函数和模块化编程.ipynb
- 4.1 函数的定义、调用与返回值.ipynb
- 4.2 函数的参数传递.ipynb
- 4.3 变量的作用域.ipynb
- 4.4 匿名函数.ipynb
- 4.5 递归.ipynb
- 4.6 内置函数.ipynb
- 4.7 模块化程序设计.ipynb
- 5.1 序列通用操作.ipynb
- 5.1.1 索引.ipynb
- 5.1.2 切片.ipynb
- 5.1.3 序列拼接与重复.ipynb
- 5.1.4 成员测试.ipynb
- 5.2.1 字符串的创建.ipynb
- 5.2.2 字符串常量.ipynb
- 5.2.4 字符串的遍历.ipynb
- 5.2.5 文件遍历.ipynb
- 5.2.6 字符串的处理方法.ipynb
- 5.2.7 字符串格式化.ipynb
- 5.2.8 转义字符.ipynb
- 5.3 random 模块及其应用.ipynb
- 6.1 元组.ipynb
- 6.2 列表.ipynb
- 6.2.1 列表的创建.ipynb
- 6.2.2 列表的更新.ipynb
- 6.2.3 列表的删除.ipynb
- 6.2.4 列表的排序.ipynb
- 6.2.5 列表赋值与复制.ipynb
- 6.2.6 列表推导式.ipynb
- 6.2.8 常用内置函数.ipynb
- 6.2.9 列表嵌套及其排序.ipynb
- 6.3 列表综合应用.ipynb
- 7.1.1 集合的创建.ipynb
- 7.1.2可变集合类型的操作.ipynb
- 7.1.3 成员关系.ipynb
- 7.1.4 集合关系.ipynb
- 7.1.5 集合运算.ipynb
- 7.2.1 字典创建.ipynb
- 7.2.2 获取字典值.ipynb
- 7.2.3 修改字典值.ipynb
- 7.2.4内置函数与方法.ipynb
- 7.2.5字典排序输出.ipynb
- 7.3 集合与字典的应用.ipynb
- 8 中 numpy 概述.ipynb
- 8 中panda 库.ipynb
- 8.1 文件的打开与关闭.ipynb
- 8.2 文件读写操作.ipynb
- 8.3 文件的应用.ipynb
- 8.4 numpy 文件操作.ipynb
- 8.4.2 and 3.ipynb
- 8.5.1 pandas文件读写.ipynb
- 8.5.2 and 3 and 4.ipynb
- 9.1 matplotlib 线性图.ipynb
- 9.1.5 数据文化绘图.ipynb
- 9.2 非线性图.ipynb
- 9.3 词云.ipynb
- _overview.md
- _readme.ipynb
- coding_here.ipynb
- dream.png
- score.txt
- score_total.csv
- 成绩分析综合.json
4.2 函数的参数传递.ipynb @master — view markup · raw · history · blame
4.3 函数的参数传递¶
当函数定义里有多个参数时,其参数的传递形式主要有以下五种:__位置传递__、__关键字__、__默认值传递__、__包裹传递__和__解包裹传递__。
Python 中一切皆为__对象__,数字是对象,列表是对象,函数也是对象。而变量是对象的一个__引用__,对象的操作都是通过引用来完成的。
函数调用过程中,__传递的是对象__。参数的传递本质上是名字到对象的__绑定过程__。
默认情况下,参数可以按位置或显式关键字传递给 Python 函数。为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置、按位置或关键字,还是仅按关键字传递。
函数定义如下:下:下:
/ 和 是可选的。这些符号表明形参如何把参数值传递给函数:位置、位置或关键字、关键字。
关键字形参也叫作命名形参。函数定义中未使用 / 和 时,参数可以按位置或关键字传递给函数。
4.3.1 位置传递¶
位置固定,参数传递时按照形式参数__定义的顺序__提供实际参数。 其优点是使用方便,缺点是当参数数目较多时,参数对应容易混淆。且要求传入参数的数量必须和定义函数时参数的数量相同。
仅限位置 时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在 / (正斜杠)前。/ 用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有 /,则表示没有仅限位置形参。
def fun(name, city, hobby):
'''接收三个字符串作为参数,返回一个进行自我介绍的字符串'''
return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)
n,c,h = input().split() # 根据空格切分输入字符串,分别赋值给n,c,h
print(fun(n,c,h)) # 根据实参变量n,c,h的顺序传递参数或值给形参name, city, hobby
调用fun()函数时,将实际参数n、c、h这三个字符串对象按顺序赋值给形式参数name、city、hobby,或者说将三个变量标签name、city、hobby按出现的顺序分别贴在"夏琦"、"武汉"、"羽毛球"这三个字符串对象上。
在定义fun()函数时,参数name、city、hobby尚未绑定对象,没有值。
只有经过函数调用,才会把调用时的参数值赋值给形式参数,函数体中的变量才有了值。
4.3.2 关键字传递¶
关键字传递是指,在函数调用时__提供__实际参数所对应的__形式参数__的名称,根据__参数名称来传递参数__。
关键字并不需要遵守位置的对应关系。其优点是明确标示实际参数和形式参数的对应关系,参数的书写顺序更灵活。缺点是增加了函数调用时的代码书写量。
def fun(name, city, hobby):
return '我的名字是{},来自{},我的爱好是{}'.format(name, city, hobby)
n,c,h = input().split() # 切分字符串,分别赋值给n,c,h
print(fun(hobby = h, city = c,name = n)) # 根据关键字name, city, hobby来传递参数,关键字传递时顺序无关
位置传递和关键字传递__可以混用__。但要注意的是,混用时,按__位置传递__的参数要出现在按__关键字传递__的参数__之前__。否则,编译器无法明确知道除关键字以外的参数出现的顺序。
def fun(name, city, hobby):
return '我的名字是{},来自{},我的爱好是{}'.format(name, city, hobby)
n,c,h = input().split() # 切分字符串,分别赋值给n,c,h
print(fun(n, hobby = h, city = c)) # 位置参数n出现在关键字参数h和c之前
在定义函数时,我们可以在参数列表中用“/”设置强制位置参数(positional-only arguments)。用“*”设置命名关键字参数。
所谓强制位置参数,就是调用函数时只能按照参数位置来接收参数值的参数;而命名关键字参数只能通过“参数名=参数值”的方式来传递和接收参数,大家可以看看下面的例子。
def fun(name, city, hobby, /): # /前面的参数是强制位置参数
"""接收三个字符串作为位置参数,返回一个进行自我介绍的字符串"""
return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)
print(fun('夏琦', '武汉', '羽毛球')) # 可以按位置传递参数
# 输出 我的名字是夏琦,来自武汉,我的爱好是羽毛球。
def fun(name, city, hobby, /): # /前面的参数是强制位置参数
"""接收三个字符串作为位置参数,返回一个进行自我介绍的字符串"""
return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)
# 下面的代码会产生TypeError错误,错误信息提示“强制位置参数是不允许给出参数名的”
# TypeError: fun() got some positional-only arguments passed as keyword arguments: 'city, hobby'
n, c, h = '夏琦', '武汉', '羽毛球'
print(fun(n, hobby=h, city=c)) # 传入一个位置参数和两个关键字参数
def fun(name, *, city, hobby): # *后面的参数是强制关键字参数
"""接收三个字符串,一个位置参数两个关键字参数,返回一个进行自我介绍的字符串"""
return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)
n, c, h = '夏琦', '武汉', '羽毛球'
print(fun(n, hobby=h, city=c)) # 传入一个位置参数和两个关键字参数
# 输出 我的名字是夏琦,来自武汉,我的爱好是羽毛球。
def fun(name, *, city, hobby): # *后面的参数是强制关键字参数
"""接收三个字符串,一个位置参数两个关键字参数,返回一个进行自我介绍的字符串"""
return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)
# 下面的代码会产生TypeError错误,错误信息提示“函数只能接收一个位置参数,但传递了3个位置参数”
# TypeError: fun() takes 1 positional argument but 3 were given
print(fun('夏琦', '武汉', '羽毛球')) # 传入三个位置参数
4.3.3 默认值传递¶
在定义函数的时候,使用形如city='武汉'的方式,可以给形式参数赋予_默认值(default)__。在函数调用时,如果该参数得到传入值,按传入值进行计算,否则使用默认值。
def fun(name, city, hobby='唱歌'):
return '我的名字是{},来自{},我的爱好是{}。'.format(name, city, hobby)
n,c = input().split() # 切分字符串,分别赋值给n,c,例如输入:夏琪 武汉
print(fun(n, c)) # 默认值参数可以不传值
# 输出: 我的名字是夏琪,来自武汉,我的爱好是唱歌。
print(fun(n, c, '游泳')) # 传值时,默认值会被传入的值替换
# 输出: 我的名字是夏琪,来自武汉,我的爱好是游泳。
可以用列表存储输入,再用星号*解包传递给函数,可做到传递任意数量的参数。
def fun(name, city, hobby='唱歌'):
return '我的名字是{},来自{},我的爱好是{}。'.format(name, city, hobby)
ls = input().split() # 切分字符串得到列表,例如输入:夏琪 武汉,得到['夏琪', '武汉']
print(fun(*ls)) # ['夏琪', '武汉']解包为:'夏琪', '武汉'
# 输出: 我的名字是夏琪,来自武汉,我的爱好是唱歌。
ls = input().split() # 切分字符串得到列表,例如输入:夏琪 武汉 游泳,得到['夏琪', '武汉', '游泳']
print(fun(*ls)) # ['夏琪', '武汉', '游泳']解包为:'夏琪', '武汉', '游泳'
# 输出: 我的名字是夏琪,来自武汉,我的爱好是游泳。
需要注意的是,__默认值参数__必须放在必选参数__之后__。当函数的参数有多个时,默认值参数必须在后面,非默认值参数在前面。
也就是说,__一旦__出现了带默认值的参数,__后面的其他参数都必须带默认值了__。
def fun( city,name='夏琪', hobby='唱歌'): #语法错误,city 是非默认值参数,出现在默认值参数hobby的前面了
return '我的名字是{},来自{},我的爱好是{}。'.format(name, city, hobby)
n,c,h = input().split() # 切分字符串,分别赋值给n,c,h
print(fun(n,c,h)) # 调用函数
练一练
利用Python中支持默认值参数的特性,修改上一节里定义的幂函数power(x,n),使其默认计算x的平方。
#修改后的power(x,n)函数
需要注意的是,默认值参数可以指向不可变对象,如整型(int)、字符串(string)、浮点型(float)、元组(tuple)等,不能指向字典(dict)和列表(list)等可变对象。
def fun(x, ls = []): # 这里默认参数ls指向了空列表,列表是可变对象
ls.append(x) # 在列表ls的末尾追加一个元素
return ls # 返回ls
print(fun(1)) # 第一次调用,输出 [1]
print(fun(3)) # 第二次调用,输出 [1, 3]
print(fun(5)) # 第三次调用,输出 [1, 3, 5]
按函数调用规则,每次函数调用时,形参都会被重新赋值。即在三次调用中,形参x分别被赋值为1,3,5,带缺省值的形参ls每次应该被重新赋值为空列表。
但程序的运行结果表明,在多次调用过程中,__ls并没有被重新赋值为空列表__,导致ls中的元素累积下来。 分析其原因,ls是可变对象,在函数定义时被创建,__其后所有函数调用都引用这个列表对象__。Python规定参数传递都是传递的引用,也就是传递给函数的是原变量实际所指向的内存空间。而append()方法并不会改变列表的内存空间,也就是说不会重新创建列表对象,只是向其中增加元素。所以每次调用该函数时,一直引用函数定义时创建的列表对象ls,__导致元素累积__。
如果一定要用这种方法的话,可以做如下修改:
def fun(x, ls = None): # ls为默认值参数,设为不可变对象None
if ls is None: # 若ls值为None,说明是重新调用,将列表置为空
ls = []
ls.append(x)
return ls
print(fun(1)) # 第一次调用,输出 [1]
print(fun(3)) # 第二次调用,输出 [3]
print(fun(5)) # 第三次调用,输出 [5]
4.3.4 包裹传递¶
包裹传递也称为不定参数传递,用于在定义函数时不能确定函数调用时会传递多少个参数时使用。函数每次调用时,传递的参数数量可以不同。
- 当传入参数是位置传递时,所有传入参数被收集打包合并成一个元组,再传递给函数。
def add(*number):
"""接收不确定数量位置传递的参数,合并为一个元组number在函数体内使用"""
print(number) # 查看参数类型,元组
result = 0
for i in number:
if type(i) in (int, float): # 对参数进行了类型检查(数值型的才能求和)
result = result + i
return result
if __name__ == '__main__':
print(add(1, 3, 5, 7, 9))
print(add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
print(add(1, 2, 'hello', 3.45, 6)) # 12.45
- 当传入参数是关键字传递时,所有传入的关键字参数被收集打包合并成一个字典,再传递给函数。
def add(**number):
"""接收不确定数量的关键字参数,合并为一个字典number在函数体内使用"""
print(number)
return sum(number.values())
if __name__ == '__main__':
print(add(a=1, b=3, c=5))
print(add(m=1, n=2, o=3, p=4, q=5, i=6, j=7, k=8))
参数列表中的**kwargs可以接收0个或任意多个关键字参数
调用函数时传入的关键字参数会组装成一个字典(参数名是字典中的键,参数值是字典中的值)
如果一个关键字参数都没有传入,那么kwargs会是一个空字典
def foo(*args, **kwargs):
print(args)
print(kwargs)
foo(3, 2.1, True, name='骆昊', age=43, gpa=4.95)
4.3.5 解包裹传递¶
“*”“**”也可以以函数调用时使用,此时称为解包裹传递。
def add(a, b, c):
"""接收三个位置传递参数,返回其加和"""
return a + b + c
if __name__ == '__main__':
num1 = (1, 3, 5)
print(add(*num1))
num2 = {'a': 1, 'b': 2, 'c': 3}
print(add(**num2))
函数调用总是会给形参列表中列出的所有形参赋值,或是用位置参数,或是用关键字参数,或是用默认值。 如果存在 "identifier" 这样的形式,它会被初始化为一个元组来接收任何额外的位置参数,默认为一个空元组。 如果存在 "**identifier" 这样的形式,它会被初始化为一个新的有序映射来接收任何额外的关键字参数,默认为一个相同类型的空映射。
在 "" 或 "*identifier" 之后的形参都是仅限关键字形参因而只能通过关键字参数传入。
在 "/" 之前的形参都是仅限位置形参因而只能通过位置参数传入。