本章内容
- 函数基本语法及特征
- 参数与局部变量
- 返回值
- 嵌套函数
- 递归
- 匿名函数
- 函数式编程介绍
- 高阶函数
- 内置函数
一、函数基本语法及特征
函数是什么?
函数一词来源于数学,但编程中的【函数】概念,与数学中的函数是有很大不同的。编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在java里面叫做method。
定义:函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
语法定义:
1 def sayhi():#函数名
2 print("Hello, I'm nobody!")
3
4 sayhi() #调用函数
可以带参数:
1 #下面这段代码
2 a,b=5,8
3 c = a**b
4 print(c)
5
6 #改成用函数写
7 def calc(x,y)
8 res = x**y
9 return res #返回函数执行结果
10
11 c = calc(a,b) #结果赋值给c变量
12 print(c)
二、函数参数与局部变量
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量。在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
1 def calc(x,y): #这里x,y为形参
2 res = x**y
3 return res
4
5 c = calc(a,b) #这里a,b是实参
6 print(c)
默认参数
def stu_register(name,age,country,course):
print("--------注册学生信息---------")
print("姓名:",name)
print("年龄",age)
print("国籍",country)
print("课程",course)
stu_register("王山炮",22,"CN","Python")
发现country这个参数基本都是“CN”,就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是中国,这就是通过默认参数实现的,把country变成默认参数非常简单
def stu_register(name,age,course,country="CN"):
#默认参数需要放到形参的后面
这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。
关键参数
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可,但记住一个要求就是,关键参数必须放在位置参数之后。
stu_register(age=22,name='alex',course="python",)
非固定参数
若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数*args
1 def stu_register(name,age,*args):
2 #*args 会把多传入的参数变成一个元组形式
3 pirnt(name,age,args)
4
5 stu_register("Lyon",20)
6 #输出
7 #Lyon 20 () #后面这个()就是args,只是因为没传值,所以为空
8
9 stu_register("Jack",32,"CN","Python")
10 #输出
11 # Jack 32 ('CN', 'Python')
还可以有一个**kwargs
1 def stu_register(name,age,*args,**kwargs):
2 # *kwargs 会把多传入的参数变成一个dict形式
3 print(name,age,args,kwargs)
4
5 stu_register("Lyon",20)
6 #输出
7 #Lyon 20 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
8
9 stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
10 #输出
11 # Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
局部变量
1 name = "Lyon"
2 def the_name(name):
3 print("one name", name)
4 name = "Charlie"
5 print("two name", name)
6
7
8 print(name)#第一个name打印的是全局变量的name
9 name = "yangyong"
10 the_name(name)#调用函数全局变量name将“yangyong”赋值进去
11 print(name)#调用函数之后name并没有因为函数内部的赋值而改变
12
13
14 #输出
15 #Lyon
16 #one name yangyong
17 #two name Charlie
18 #yangyong
全局与局部变量
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量同名时:
在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
三、返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,所以也可以理解为return语句代表着函数的结束
- 如果未在函数中指定return那这个函数的返回值为None
四、嵌套函数
嵌套函数顾名思义就是函数里面再套函数
1 name = "Lyon"
2 def chane_name():
3 name = "Lyon1"
4 def chane_name1():
5 name = "Lyon2"
6 print("第三层打印",name)
7
8 chane_name1()#调用内层函数
9 print("第二层打印",name)
10 chane_name()
11 print("最外层打印",name)
这里如果在最外层调用chane_name1()会出现什么效果?
没错,出错了,要想调用chane_name1()那么首先要调用change_name(),只有在chane_nanme()里面才能找到chane_name()函数
五、递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
1 def numb(x):
2 print(x)
3 if int(x/2)>0:
4 return numb(int(x/2))
5 print("-->",x)
6 numb(50)
7
8 输出
9 50
10 25
11 12
12 6
13 3
14 1
15 --> 1
递归特性:
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
递归的实际应例,二分查找
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
def binary_search(dataset,find_num):
print(dataset)
if len(dataset) >1:
mid = int(len(dataset)/2)
if dataset[mid] == find_num: #find it
print("找到数字",dataset[mid])
elif dataset[mid] > find_num :# 找的数在mid左面
print("