@[toc]
1.什么是函数
- 函数
(function)
由若干条语句组成,用于实现特定的功能 - 函数的本质就是对功能的封装
- 一旦定义了函数,就可以在程序中需要实现该功能的位置调用函数
- 函数名不能重复(没有重载)
2.定义和调用函数
- 使用
de
f关键字来创建python自定义函数 - 可以直接使用函数名来调用函数
语法结构:
def 函数名 (参数列表)
函数体
return 数据
- 参数列表可以为空,也可以包含多个参数
-
return
可写可不写,不写默认返回None
<1> 定义一个空函数
def test():
pass
<2> 无参函数
def test():
print('in test')
test()
运行结果
in test
==尽管定义了函数,只要不调用函数,那这个函数是不会执行的==
def hh():
print('hello')
#没有调用这个函数,该函数不执行
<3> 有参函数 (参数---argument/arg)
def test1(arg):
print('in test')
test1(1)
def test2(arg):
print('in test',arg)
#参数类型没有要求,可以是任意类型
test2(1)
test2('hello')
test2([100,200])
def test3(arg,arg1,arg2):
print('in test',arg,arg1,arg2)
# 1-->arg python-->arg1 [1,2]-->arg2
test3(1,'python',[1,2])
运行结果
in test
in test 1
in test hello
in test [100, 200]
in test 1 python [1, 2]
- 参数类型没有要求,可以是任意类型
- 参数的个数没有要求
3. 返回值
def test(arg,arg1,arg2):
print('in test',arg,arg1,arg2)
return 1 #返回1
ret=test(1,2,3) #调用test(1,2,3)函数,然后把返回值给ret变量
print(ret)
运行结果
in test 1 2 3
1
==可以返回任何类型==
def test1(arg,arg1,arg2):
print('in test1',arg,arg1,arg2)
return [4,5]
ret=test1(1,2,3)
print(ret)
def test2(arg,arg1,arg2):
print('in test2',arg,arg1,arg2)
return [arg,arg1,arg2]
ret=test2(1,2,3)
print(ret)
运行结果
in test1 1 2 3
[4, 5]
in test2 1 2 3
[1, 2, 3]
==如果没有return那么就返回None return|return None |不写==
def test3(arg,arg1,arg2):
print('in test3',arg,arg1,arg2)
ret=test3(1,2,3)
print(ret)
def test4(arg,arg1,arg2):
print('in test4',arg,arg1,arg2)
return
ret=test4(1,2,3)
print(ret)
def test5(arg,arg1,arg2):
print('in test5',arg,arg1,arg2)
return None
ret=test5(1,2,3)
print(ret)
运行结果
in test3 1 2 3
None
in test4 1 2 3
None
in test5 1 2 3
None
练习题:
#我们系统函数test6 如果都是整数 那么返回数组[1,2,3]
#如果参数全是字符串 就返回 arg arg1 arg2 'welcome to python'
def test6(arg,arg1,arg2):
#判断参数的类型
#isinstance 是系统的 用来判断参数是否是你想要的那个类型
if isinstance(arg,int) and isinstance(arg1,int) and isinstance(arg2,int):
return [arg,arg1,arg2]
if isinstance(arg,str) and isinstance(arg1,str) and isinstance(arg2,str):
return arg+' '+arg1+' '+arg2
#如果参数并不都是整数或者并不都是字符串,那就返回'Error'
return 'Error'
c=test6(1,2,3)
print(c)
c=test6('welcome','to','python')
print(c)
c=test6(1,2,'python')
print(c)
运行结果
[1, 2, 3]
welcome to python
Error
4.形参和实参
形参:
- 形参变量只有在被调用时才分配内存单元,在调用结束时,即可释放预分配的内存单元
- 形参只在函数内部有效
- 函数调用结束返回主调用函数后则不能再使用该形参变量
实参:
- 实参可以是常量、变量、表达式、函数等
- 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传递给形参
- 应预先用赋值,输入等办法是参数获得确定值
def calc(x,y): #x,y是形参
res=x**y
return res
c=calc(2,3) #2,3是实参
#有人想这个不就是 x=2,y=3的赋值操作,那就可以直接输出x,y
#但是不要忘了形参只有在被调用时才分配内存单元
#print(x) 错误
#print(y) 错误
print(c)
运行结果
8
5.函数参数
def test7(name,age,score):
print(name,age,score)
<1>普通参数
test7('yang',18,80)
运行结果
yang 18 80
==普通参数的参数顺序不能改变==
tset7(18,'yang',80) 是错的
<2> 关键字参数
==顺序可以随便设置==
test7(name='yang',age=18,score=80)
test7(age=18,score=80,name='yang')
运行结果
yang 18 80
yang 18 80
<3> 普通参数和关键字参数混合使用
- 注意
python
要求 普通参数和关键字参数如果混合使用那么你必须==先传普通参数,然后再传关键字参数==
test7('yang',18,score=80)
test7('yang',age=18,score=80)
test7(name='yang',age=18,score=80)
#test7('yang',age=18,80) 错误
#test7('yang',70,age=18) 错误 70传给age而后面的参数又给age赋值了一个数,那就没有参数传给score了
运行结果
yang 18 80
yang 18 80
yang 18 80
<4>默认参数
def test8(name,age,score=60):
print(name,age,score)
#因为已经有一个参数有了默认值,所以我们传入两个参数就可以
test8('yang',18)
#当然也可以传三个参数,但是已经默认的那个参数如果也要传的话,它会自动变为传入的数值
test8('yang',18,70)
运行结果
yang 18 60
yang 18 70
==默认参数后面不能有普通参数==
def test9(name,age=18,score=80):
print(name,age,score)
test9('yang')
# def test9(name,age=18,score): 错误
运行结果
yang 18 80
<5> 可变长参数
(1) *args
-
*args
表示一个可变元组 -
args
就是一个元组 元组就是只读的数组/列表 - 参数名就是
args
-
*
表示args
里面的参数可变
def test10(*args):
print(args)
test10(1,2,3) #可以随便添加参数
运行结果
(1, 2, 3)
def test11(*args):
print(args,type(args)) #只输出args的值和类型
value=0
for i in args: #因为args是一个元组,所以需要遍历才能获取每个元素
value+=i
return value
c=test11(1,2,3,4)
print(c)
c=test11() #没有给args传值
print(c)
运行结果
(1, 2, 3, 4)
10
()
0
这个可变参数 前面两个参数v1,v2是默认参数,后面的参数是可变的
def test12(v1,v2,*args):
print(args,type(args)) #只输出args的值和类型
value=0
for i in args:
value+=i
return value
c=test12(1,2) #v1=1,v2=2,没有给args传值
print(c)
运行结果
()
0
def test13(v1,v2,*args):
print(args,type(args)) #只输出args的值和类型
value=0
for i in args:
value+=i
return value
c=test13(1,2,3) #v1=1,v2=2,args=3
print(c)
运行结果
(3,)
3
def test14(v1,v2,*args):
print(args,type(args)) #输出args和args的类型
value=(v1+v2) #value不像前两个赋值为0,现在的value已经把v1,v2提前加起来了
for i in args:
value+=i
return value
c=test14(1,2,3) #v1=1,v2=2,args=3
print(c)
运行结果
(3,)
6
可变参数传数组/列表
*list1
就是args
def test14(v1,v2,*args):
print(args,type(args)) #输出args和args的类型
value=(v1+v2) #value不像前两个赋值为0,现在的value已经把v1,v2提前加起来了
for i in args:
value+=i
return value
list1=[1,2,3,4]
c=test14(1,2,1,100,*list1) #v1=1 v2=2 1,100,*list1就是args
#上面的相当于拆成 c=test14(1,2,1,100,1,2,3,4)
print(c)
(1, 100, 1, 2, 3, 4)
114
(2) **kwargs
- 可变参数处理关键字参数
-
kwargs
表示 关键字可变参数 -
*
表示普通可变参数(positional
位置参数) -
**
表示关键字可变参数 -
kwargs
是一个字典
def test15(**kwargs):
print(kwargs,type(kwargs))
value=0
for key in kwargs:
v=kwargs[key] #获取字典里的值
if isinstance(v,int) or isinstance(v,float): #如果v是整数或者是浮点数那就执行下面的加法运算
value+=v
return value
test15(name='yang')
c=test15(name=10,b=1,c=2,d=3,e=4,f=100.56)
print(c)
运行结果
{'name': 'yang'}
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
120.56
==可变参数支持位置参数/普通参数和关键字参数==
def test16(*args,**kwargs):
print(args)
print(kwargs)
value=0
return value
c=test16(1,2,3,name=10,b=1,c=2,d=3,e=4,f=100.56)
print(c)
运行结果
(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
0
def test17(*args,**kwargs):
print(args)
print(kwargs)
value=0
#先处理位置参数/普通参数
for i in args: #遍历元组
value+=i
for i in kwargs: #遍历字典
v=kwargs[i]
value+=v
return value
c=test17(1,2,3,name=10,b=1,c=2,d=3,e=4,f=100.56) #若有字符串的参数还需要判断并不参与加法运算
print(c)
运行结果
(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
126.56
参数解开
dict2={'name':10,'b':1,'c':2,'d':3,'e':4,'f':100.56}
tuple2=(1,2,3)
# *tuple2 表示把(1,2,3)---->1,2,3
# **dict2 表示把{'name':10,'b':1,'c':2,'d':3,'e':4,'f':100.56}--->name=10,b=1,c=2,d=3,e=4,f=100.56
# **的作用就是把dict2从字典转换成关键字参数
c=test17(*tuple2,**dict2)
print(c)
运行结果
(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
126.56
6.递归函数
递归特性
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出
- 在计算机中,函数调用时通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的。所以,递归调用的次数过多,会导致栈溢出
def calc(n):
print(n)
if int(n/2)==0:
return n
res=calc(int(n/2))
return res
calc(10)
运行结果
10
5
2
1
def calc1(n):
print(n)
if int(n/2)==0:
return n
res=calc1(int(n/2))
return res
res=calc1(10)
print(res)
运行结果
10
5
2
1
1
res的值就是最后得到的1
递归函数相当于问路,我问1号朋友怎么去目的地,1号不知道他去2号,2号不知道他去问3号,3号说我知道怎么走,这时,我们还要返回正确路线给问路人我,3号告诉2号,2号告诉1号,1号再传达给我
person_list=['小明','小李','小红','小蓝']
def ask_way(person_list):
print('-'*60) #打印一条分界线
if len(person_list)==0: #到最后一个人还不知道怎么走
return '没人知道'
person=person_list.pop(0) #每次都把列表里的第0个元素删除并赋值给person
if person=='小红': #小红知道正确的路线
return '%s说:我知道路,左走一百米就到了'%person
print('hi 美女[%s],请问你知道华林在哪吗?'%person) #每当问到一个人就输出这句话
print('%s回答道:不好意思,我不是很清楚,我帮你问问%s...'%(person,person_list))
res=ask_way(person_list) #把继续问的人的结果赋值给res,当结果问到时就一层一层的返回给问路的人,并输出下面的话
print('%s问的结果是:%res'%(person,res))
return res
res=ask_way(person_list)
print(res)
运行结果
------------------------------------------------------------
hi 美女[小明],请问你知道华林在哪吗?
小明回答道:不好意思,我不是很清楚,我帮你问问['小李', '小红', '小蓝']...
------------------------------------------------------------
hi 美女[小李],请问你知道华林在哪吗?
小李回答道:不好意思,我不是很清楚,我帮你问问['小红', '小蓝']...
------------------------------------------------------------
小李问的结果是:'小红说:我知道路,左走一百米就到了'es
小明问的结果是:'小红说:我知道路,左走一百米就到了'es
小红说:我知道路,左走一百米就到了