4 函数
在Python中,函数定义的基本形式如下:
def 函数名(函数参数):
函数体
return 表达式或者值
- 采用def关键字进行函数的定义,不用指定返回类型
- 函数参数可以是零个、一个或者多个,函数参数也不需要指定类型
- 执行到
return
时代表函数执行完毕,如果没有return
会自动返回空值 - Python允许嵌套定义函数
- 如果函数返回多个值,会将多个值打包成元组返回。
- 函数定义前不允许调用该函数
自定义一个求绝对值的my_abs
函数为例:
def my_abs(x):
if x >= 0:
return x
else:
return -x
如果想定义一个什么事也不做的空函数,可以用pass
语句:
def nop():
pass
4.1 函数的参数
形参全称是形式参数,在用def
关键字定义函数时函数名后面括号里的变量称为形式参数。
实参全程是实际参数,在调用函数时提供的值或者变量成为实际参数
例:
#这里的a和b就是形参
def add(a,b):
return a+b
#下面是调用函数
add(1,2) #这里的1和2就是实参
x = 2
y = 3
add(x,y) #这里的x和y就是实参
绝大数情况下,在函数内部直接修改形参的值不会影响实参,例:
def addOne(a):
a +=1
print(a) #输出4
a = 3
addOne(a)
print(a) #输出3
但有些情况下,可以通过特殊的方式在函数内部修改实参的值
def modify1(m,K):
m = 2
K = [4,5,6]
return
def modify2(m,K):
m = 2
K[0] = 0 #同时修改了实参的内容
return
#主程序
n = 100
L = [1,2,3]
modify1(n,L)
print(n)
print(L)
modify2(n,L)
print(n)
print(L)
'''
100
[1, 2, 3]
100
[0, 2, 3]
'''
如果传递给函数的实参是可变序列,并且在函数内部使用下标或可变序列自身的方法增加、删除元素或修改元素时,实参也会得到相应的修改
def modify(v,item): #为列表增加元素
v.append(item)
#主程序
a = [2]
modify(a,3)
print(a)
# [2, 3]
再如修改字典元素值
def modify(d):
d['age'] = 38
#主程序
a = {'name':'Dong','age':37,'sex':'Male'}
print(a) # {'name': 'Dong', 'age': 37, 'sex': 'Male'}
modify(a)
print(a) # {'name': 'Dong', 'age': 38, 'sex': 'Male'}
4.2 函数参数的类型
4.2.1 位置参数
位置参数(positional arguments)是比较常用的形式,调用函数时实参和形参的顺序必须严格一致,并且实参和形参的数量必须相同
例:
def demo(a.b,c):
print(a,b,c)
demo(1,2,3) #按位置传递参数
#1,2,3
demo(1,2,3,4) #demo() takes 3 positional arguments but 4 were given
#实参与形参数量必须相同
4.2.2 默认值参数
默认值参数是指它能够给函数参数提供默认值
def 函数名(……,形参名=默认值):
函数体
return 返回值
注意:默认值参数必须在位置参数之后
例:
def power(x,n=2):
s = 1
while n>0:
n = n - 1
s = s * x
return s
当我们调用power(5)
的时候,相当于调用power(5,2)
,从上面的例子可以看出,默认参数可以简化函数的调用
设置默认参数时,有几点要注意:
- 默认参数必须在位置参数之后
- 设置默认参数可以参考把变化大的参数放前面,变化小的参数可以作为默认参数
- 默认参数必须指向不变对象
例:
def add_list(L=[]):
L.append('END')
return L
上面的代码意思是传入一个list,再添加一个’END’返回,正常调用不会出现问题,但是如果多次调用add_end()
就会出现问题
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
Python函数在定义的时候,默认参数L
的值就被计算出来了,即[]
,因为默认参数L
也是一个变量,它指向对象[]
,每次调用该函数,如果改变了L
的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]
了。
定义默认参数要牢记一点:默认参数必须指向不变对象!
要修改上面的例子,我们可以用None
这个不变对象来实现:
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
为什么要设计str
、None
这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。
4.2.3 关键字参数
关键字参数是通过参数名字匹配的,不需要严格按照参数定义时的位置来传递参数。
例:
def display(a,b):
print(a)
print(b)
#下面两句达到的效果是相同的
display(a = 'word',b = 'hello')
display(b = 'hello',a = "world")
'''
word
hello
world
hello
'''
4.2.4 可变参数
可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
例:一个人可以有多个昵称,此时无法确定参数的个数,只需要在参数前面加上*
或者**
def storename(name,*nickName):
print('real name is %s'%name)
for nickname in nickName:
print("昵称",nickname)
#主程序
storename('张三')
storename('张三','小张')
storename('张三','zhangsan')
'''
real name is 张三
real name is 张三
昵称 小张
real name is 张三
昵称 zhangsan
'''
*
和**
表示能够接受0到任意多个参数
*
表示将没有匹配的值都放到同一个元组中**
表示将没有匹配的值都放到一个字典中
假如使用**
def demo(**p):
for item in p.items():
print(item)
demo(x=1,y=2,z=3)
'''
('x', 1)
('y', 2)
('z', 3)
'''
假如使用*
def demo(*p):
for item in p:
print(item,end=' ')
demo(1,2,3)
#1 2 3
4.3 变量的作用域
1 局部变量
在函数内定义的变量只在该函数内起作用,称为局部变量。变量起作用的范围称为变量的作用域。
例:
def fun():
x = 3
count = 2
while count > 2:
print(x)
count = count - 1
fun()
print(x) # name 'x' is not defined
2 全局变量
全局变量在函数外定义,作用域是整个程序。全局变量可以直接在函数里面使用,如果要在函数内改变全局变量值,必须使用global
关键字进行声明。
x = 2 #全局变量
def fun1():
print(x,end=" ")
def fun2():
global x #在函数内部改变全局变量值必须使用global关键字
x = x + 1
print(x,end=" ")
fun1()
fun2()
print(x,end=" ")
#2 3 3
4.4 函数参数序列解包
传递参数时,可以通过在实参序列前加一个*
将其解包,然后传递给多个单变量形参。
def demo(a, b, c):
return a+b+c
seq = [1, 2, 3]
print(demo(*seq))
#6
tup = (1, 2, 3)
print(demo(*tup))
#6
>>> Set = {1, 2, 3}
>>> print(demo(*Set))
#6
>>> dic = {1:'a', 2:'b', 3:'c'}
>>> print(demo(*dic))
#6
>>> print(demo(*dic.values()))
#abc
>>> print(demo(*dic.keys()))
#6
如果函数实参是字典,可以在前面加**
进行解包,等价于关键参数。
>>> def demo(a, b, c):
return a+b+c
>>> dic = {'a':1, 'b':2, 'c':3}
>>> print(demo(**dic))
#6
>>> print(demo(a=1, b=2, c=3))
#6
>>> print(demo(*dic.values()))
#6
4.5 闭包和递归
闭包指函数的嵌套。可以在函数内部定义一个嵌套函数,将嵌套函数视为一个对象
例:
def func_lib():
def add(x,y):
return x+y
return add #返回函数对象
fadd = func_lib()
print(fadd(1,2))
#3
函数在执行的过程中直接或间接的调用自己本身,称为递归调用。
例:求1~5的平方和
def f(x):
if x==1:
return x
else:
return(f(x-1)+x*x) #调用f()函数本身
print(f(5))
# 55