1、函数的定义
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。其特性如下:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
2、语法定义
1 def func1(): 2 '''test1''' #声明函数的作用 3 print("test function1") 4 return 0 #返回值 5 6 func1() #调用函数 7 x = func1() #将函数返回值赋值给x 8 print(x)
3、函数返回值
返回值个数=0,返回None
返回值个数=1,返回object
返回值个数>1,返回tuple
4、带有参数的函数
4.1、普通参数
函数的参数又分为形式参数和实际参数:
- 形参变量:只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。
- 实际参数:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值。
1 def func1(x,y): 2 print(x) 3 print(y) 4 5 func1(1,2) #位置参数,实参与形参一一对应,与位置有关 6 func1(y=2,x=1) #关键字参数,与位置无关。但是需要注意的是:关键字参数必须在位置参数之后。 7 8 func1(10,y=20) 9 # func1(x=10,20) 这样写不行,因为关键字参数不能写在位置参数前面
4.2、默认参数
默认参数必须放在形参和*args的后面,**kwargs的前面。
1 #现有代码如下: 2 def stu_register(name,age,country,course): 3 print("----注册学生信息------") 4 print("姓名:",name) 5 print("age:",age) 6 print("国籍:",country) 7 print("课程:",course) 8 9 stu_register("王山炮",22,"CN","python_devops") 10 stu_register("张叫春",21,"CN","linux") 11 stu_register("刘老根",25,"CN","linux") 12 13 #发现country都是相同的,因此可以给该参数一个默认值: 14 def stu_register(name,age,course,country='CN'): #默认参数必须放形参的后面 15 print("----注册学生信息------") 16 print("姓名:",name) 17 print("age:",age) 18 print("国籍:",country) 19 print("课程:",course) 20 21 stu_register("王山炮",22,"python_devops") 22 stu_register("张叫春",21,"linux") 23 stu_register("刘老根",25,"linux")
4.3、非固定参数
若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数。非固定参数必须放置形式参数之后,且*args放置在默认参数之前,**kwargs放置在*args和默认参数之后。
1 #*args:接收N个位置参数,转换成元组 2 def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式,且*args必须放在形参之后,默认参数之前 3 print(name,age,args) 4 5 stu_register("Alex",22) #Alex 22 () #输出:Alex 22 () #后面这个()就是args,只是因为没传值,所以为空元组 6 7 stu_register("Jack",32,"CN","Python") #输出:Jack 32 ('CN', 'Python') 8 9 #注意默认参数的位置,只能放在*args之后 10 def stu_register(name,age,*args,sex="Male"): # *args 会把多传入的参数变成一个元组形式,且*args必须放在形参之后,默认参数之前 11 print(name,age,args,sex) 12 13 stu_register("Jack",32,"Python","CN") --> Jack 32 ('Python','CN') Male 14 15 #如果默认参数放在*args之前,那么会出现如下的情况: 16 def stu_register(name,age,sex="Male",*args): 17 print(name,age,sex,args) 18 19 stu_register("Jack",32,"Python","CN") --> Jack 32 Python ('CN',) # 位置参数Python传递的值会覆盖形式参数sex的默认值Male 20 # stu_register("Jack",32,sex="Male","Python","CN")这样又会报错,因为关键字参数不能出现在位置参数之前。 21 22 #*args传递参数的方式 23 def func3(*args): 24 print(args) 25 26 func3(1,2,3,4,5) 27 #如果传递列表或元组,想达到和如上一致的效果,那么就在列表或元组前加* 28 func3(*[1,2,3,4,5]) --> (1,2,3,4,5) # 站在实参的角度上,给序列(列表、元组)加上*,就是将这个序列按照顺序打散,传递给形参。站在形参的角度上,给变量加上*,就是按顺序组合所有传递过来的值。 29 func3(*(1,2,3,4,5)) --> (1,2,3,4,5) 30 #而如果直接传递列表或者元组,那么结果也是列表或元组 31 func3([1,2,3,4,5], ) --> ([1, 2, 3, 4, 5],) 32 func3((1,2,3,4,5), ) --> ((1, 2, 3, 4, 5),) 33 34 35 #**kwargs:接收N个关键字参数,转换成字典 36 37 #**kwargs传递参数的方式 38 def func4(**kwargs): 39 print(kwargs) 40 41 func4(a=1,b=2) #和如下的传参方式等价 42 43 d1 = {"a"=1, "b"=2} 44 func4(**d1) # 如果想以字典的方式传递值,那么就要在字典前加上**。道理和*args传参方式一致 45 46 #传递多种类型的参数 47 def stu_register(name,age,*args,sex="male",**kwargs): # **kwargs 会把多传入的参数变成一个字典形式,且**kwargs必须放在形参、*args和默认参数之后 48 print(name,age,args,sex,kwargs) 49 50 stu_register("Alex",22) #输出:Alex 22 () male {} #()是args,因为没传值,所以是空元组;后面这个{}就是kwargs,因为没传值,所以为空字典 51 52 stu_register("Druid",32,"python",hobby="Female",province="ShanDong") #输出:Druid 32 ('python',) male {'hobby': 'Female', 'province': 'ShanDong'}
4.4、lambda表达式
1 #普通函数 2 def func1(x): 3 return x+100 4 5 res = func1(100) 6 7 #lambda表达式,等价于上面的函数 8 func1 = lambda x:x+100 9 10 res = func1(111) 11 print(res) 12 13 #lambda表达式之多参数 14 func2= lambda x,y:x+y+100 15 16 res1 = func2(11,22) 17 print(res1) 18 19 #lambda表达式之默认参数 20 func3 = lambda x,y=22:x+y+1001 21 res2 = func3(11) 22 print(res2)
4.5、递归
如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归特性:
1. 必须有一个明确的结束条件。
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少。
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)。
堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.htm
1 def calc(num): 2 print(num) 3 if num//2 >= 1: #结束的条件 4 return calc(num//2) 5 6 calc(10) #输出:10 5 2 1
5、高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
1 def add(a,b,f): 2 return f(a)+f(b) 3 4 res = add(-10,10,abs) #将abs函数作为参数传递,然后在目标函数的内部用该函数进行计算 5 print(res)
6、闭包
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
当循环结束以后,循环体中的临时变量不会销毁,而是继续存在于执行环境中。且python的函数只有在执行时,才会去找函数体里的变量的值。
funclist = [] for i in range(3): def foo(x): print x + i flist.append(foo) for f in funclist: f(2) # --->输出结果为4 4 4。