1.函数简介
- 函数也是一个对象
- 函数用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次调用
结构如下:
语法
def 函数名([形参1,形参2,形参3....]):
代码块
注意:函数名必须符合标识符的规范(可以包含字母、数字、下划线但是不能以数字开头)
例1:列表作为函数对象实例
#列表是一个可变对象
a=[1,2,3]
b = a
b=[5,6,7] #这个操作是在给变量重新赋值,会改变变量指向的对象
print('a=',a,id(a)) #a= [1, 2, 3] 2072714764872
print('b=',b,id(b)) #b= [5, 6, 7] ![2072714764936]
a=[1,2,3]
b = a
b[0]=10 # (改对象 该对象里面的值)
#这个操作通过变量来修改对象里面的值,不会改变变量a,b所指向的对象(列表)
print('a=',a,id(a)) #a= [10, 2, 3] 2623879275080
print('b=',b,id(b)) #b= [10, 2, 3] 2623879275080
图解:
1)通过变量来修改对象里面的值,不会改变变量a,b所指向的对象(列表)
2)给变量重新赋值,会改变变量指向的对象
例2:函数需要调用才能实现其功能
# fn 为函数对象 fn()为函数调用
def fn():
print('这是一个函数')
print('黑猫')
fn()
这是一个函数
黑猫
2 函数的参数
2.1 形参和实参
- 形参(形式参数) 定义形参就相当于在函数内部声明了变量,但是并不是赋值
- 实参(实际参数)指定了形参,那么在调用函数时必须传递实参,实参将会赋值给对应的形参,简单来说有几个形参就要有几个实参
例3:在定义函数时可以在括号后面定义数量不等的形参,多个形参用逗号隔开
#定义一个函数 可以用求任意2个数的和
#在定义函数时可以在括号后面定义数量不等的形参,多个形参用逗号隔开
def s(a,b):
#print('a=',a)
#print('b=',b)
print(a,'+',b,'=',a+b )
s(1,2) #3
2.2 函数的传递方式
- 定义形参时,可以为形参指定默认值。指定了默认值以后,如果用户传递了参数则默认值不会生效。如果用户没有传递,则默认值就会生效。
def fn(a,b,c=10): #c=10该形参是默认值
print('a=',a)
print('b=',b)
print('c=',c)
fn(1,2,3) #a=1,b=2 c=3用户传递了参数则默认值不会生效
fn(1,2) #a=1,b=2,c=10 用户没有传递,则默认值就会生效
2.2.1 位置传参
- 定义:就是将对应位置的实参赋值给对应位置的形参
fn1(1,2,3) --> def fn1(a,b,c) 1-->a 2--b, 3-->c
2.2.2 关键字传参
- 定义:可以不按照形参定义的顺序去传递,而根据参数名进行传递
def fn2(a,b,c):
print('a=',a)
print('b=',b)
print('c=',c)
fn2(a=1,b=2,c=3) #位置传参和关键字传参可以混合使用 a=1,b=2,c=3
fn2(c=3,1,2) #会报错 关键字传参要在位置传参的后面
fn2(1,2,c=3) #a=1,b=2,c=3
总结:
- 函数的传递方式有两种:位置传参和关键字传参,且二者可以混合使用,但是关键字参数必须在位置参数之后
2.3 函数的实参类型
- 实参可以传递任意类型的对象
- 函数在调用的时候解析器不会检查实参的类型
几种常见类型如下:
def fn(a,b,c):
print('a=',a)
print('b=',b)
print('c=',c)
def fn3(a):
print('a=',a)
fn3(123) #int型 a= 123
fn3([1,2,3]) # 列表 a= [1, 2, 3]
fn3(True) # bool型 a= True
fn3('python') #字符型 a= python
# 实参是一个函数对象,而不是一个函数调用,因此不是fn()
fn3(fn) # a= <function fn at 0x000001B08B76D1E0>
但是注意:int类型和str类型不可相加
def fn4(a,b):
print(a+b)
fn4(1,'2') #会报错 int类型和str类型不可相加
例:实参为可变对象列表时的特殊情况
def fn5(a):
#在函数中对形参重新赋值,不会影响其他变量
#a是一个列表,修改列表里面的元素,如果形参是一个可变对象,当我们修改对象(改变对象的值)会影响
#到所指向该对象的值
a[0]=10
print('a =',a)
c=[1,2,3]
fn5(c) # a = [10, 2, 3]
print('c =',c) #c = [10, 2, 3]
# 若想要将二者关联解除,可以这样做:
# c.copy() 拷贝方式
fn5(c.copy) # a = [10, 2, 3] 相当于创建了一个c的副本,因此副本修改时,原版c不受影响
print('c =',c) # c = [1, 2, 3]
# c[:] 切片方式
fn5(c[:]) # a = [10, 2, 3]
print('c =',c) # c = [1, 2, 3]
2.4 不定长参数
- 定义函数时,可以在形参前面加一个*,这样这个形参可以获取到所有的实参,它会将所有的实参保存到一个元组中
def fn(*b):
print('b = ',b,type(b))
# *b 会接受所有的位置实参,并且会将这些实参统一保存到一个元祖中
fn(1,2,3,4,5,6,7,8) # b = (1, 2, 3, 4, 5, 6, 7, 8) <class 'tuple'>
例:求任意个参数和
def s(*b):
#定义一个变量 保存结果
r=0
for i in b:
r += i
print(r)
s(1,2,300) #303
- 带*号的形参只能有一个,可以和其他参数配合使用
def s(a,*c,b):
print('a = ',a)
print('b = ',b)
print('c = ',c)
s(1,2,300,b=50) # a = 1,b = 50,c = (2, 300)
- *形参只能接受位置参数,不能接受关键字参数
def fn(*b):
print('b = ',b)
fn(b=1,d=2,c=3) #TypeError: fn() got an unexpected keyword argument 'b'
注:引入**参数:**形参可以接收其他的关键字参数,它会将这些参数统一保存到字典当中。字典的key就是参数的名字,字典的value就是参数的值
def fn(**args):
print('args = ',args)
fn(b=1,d=2,c=3) #args = {'b': 1, 'd': 2, 'c': 3}
#*name 处理的是位置参数,**name 处理的是关键字参数
def fn1(a,*b,**c): # **形参只有一个,并且必须写在所有参数的后面
print('a =',a)
print('b =',b)
print('c =',c)
print('e =',c['e'])
fn1(1,2,3,4,e = 50, f= 80) #a = 1,b = (2, 3, 4),c = {'e': 50, 'f': 80},e =50
2.5 参数的解包
- 传递实参时,也可以在序列类型的参数前添加星号,这样它会自动的将序列中元素依次作为参数传递
def fn(a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
#实参为元组
t=(1,2,3)
fn(t[0],t[1],t[2])
fn(*t) # *t会将t中的元素依次传给形参
#结果:
a = 1
b = 2
c = 3
a = 1
b = 2
c = 3
# 实参为字典
d={'a':1,'b':2,'c':3}
fn(**d)
# 结果
a = 1
b = 2
c = 3