函数
本节导读:
- 函数的定义与特性
- 函数的创建
- 函数的参数
- 函数的返回值
- 函数的作用域(局部变量和全局变量)
- 匿名函数
- 函数的高级用法
一 函数的定义与特性
定义:
函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
二 函数的创建与调用:
# 创建函数 def sayhi(): print("Hello, I'm nobody!") # 调用函数 sayhi() #在函数名后面加括号,就是调用这个函数
三 函数的参数
- 形参和实参
形参:是函数定义时候定义的参数
实参:函数调用的时候传进来的参数
- 默认参数
以下代码,country位置不填写,则默认为“CN”,country位置填写,则传入该值,默认参数后移动到最后
def stu_register(name,age,course,country="CN"):
- 关键参数
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),但记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后
def stu_register(name, age, course='PY' ,country='CN'):
调用可以这样
stu_register("王山炮",course='PY', age=22,country='JP' )
但绝不可以这
stu_register("王山炮",course='PY',22,country='JP' )
当然这样也不行
stu_register("王山炮",22,age=25,country='JP' )
这样相当于给age赋值2次,会报错!
- 非固定参数
函数在定义时不确定用户想传入多少个参数时,就可以使用非固定参数
*arg
send_alert(msg,*arg)# 会将多个值打包成一个元组,也可以传一个元组或列表,但是要记得在传的元组或列表前加*,否则或默认次列表,为外层元组中的一个元素 send_alert(msg,*args,age) send_alert('alex','rain','eic',22) #会报错,alex后的全被*args截胡了,age得不到值 send_alert('alex','rain','eic',age = 22) #这样才正确
**kwarg
def stu_register(name,age,*args,**kwargs): # *kwargs 会把传入的键值对形式,自动打包成字典,也可以传字典,但是得在前面加**
print(name,age,args,kwargs) stu_register("Alex",22) #输出 #Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong") #输出 # Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
四 返回值:
函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回
注意
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
五 作用域(局部\全局变量):
作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。名字的可用代码范围具体又引申为局部变量和全局变量
局部变量|全局变量
- 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
- 函数内部无法修改全局变量,但可以调用全局变量
-
强行在局部修改全局变量
global name
name = ..... - 可以在局部修改全局列表,或字典内部元素的值
- 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数。
- 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。
六 匿名函数
匿名函数也叫lambda表达式,匿名函数的核心:一些简单的需要用函数去解决的问题,匿名函数的函数体只有一行
特点是
- 参数可以有多个,用逗号隔开
- 返回值和正常的函数一样可以是任意的数据类型
- 可以使用三元运算,一般与其他函数搭配使用
- 节省代码量,看着高级
与map方法搭配
l=[1,2,3,4] # def func(x): # return x*x # print(list(map(func,l))) print(list(map(lambda x:x*x,l)))
与filter方法的搭配
1 l=[15,24,31,14] # def func(x): # return x>20 # print(list(filter(func,l))) print(list(filter(lambda x:x>20,l)))
七 函数的高级用法
1 嵌套使用
多层函数嵌套使用,代码定义完成之后作用域已经生成,无法更改(在外面调用内层函数时,可以调用外层函数的值)
2高阶函数(将函数作为参数或者返回值)
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
只需满足以下任意一个条件,即是高阶函数:
- return 返回另外一个函数
- 接受一个或多个函数作为输
3 递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归特性:
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
递归的作用:
可以用于解决很多算法问题,把复杂的问题分成一个个小问题,一一解决
比如斐波那契数列,汉诺塔,多级评论树
尾递归
调用下一层时,和上一层完全无关系,只保留一层的栈数据,执行效率较高
return cal(n+1) 尾递归
return n*cal(n+1) n 还在等待下一层的结果,所有不是尾递归
递归注意:
- 默认最多递归1000层(防止占用大量内存)
- 可以修改最大递归层次
import os
sys.setreccursionlimit(1500)