定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
语法定义
# 不带参 def sayhi(): print('hi') sayhi() # 调用 # 带参 def calc(x,y): res = x+y return res c = calc(5,5) print(c) # 多个参数返回 def num(x,y): return x,y c = num(4,5) print(c)
形参与实参关系
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
默认参数
# 函数中添加默认参数数值,调用时不填写,返回默认 def num(x=2): return x c = num() print(c) c = num(4) print(c)
默认参数乱用的坑
def add_end(L=[]): L.append('End') return L # 正常调用 >>>add_end([1,2,3]) [1,2,3,'End'] # 第一次使用默认参数 >>>add_end() ['End'] # 第二次调用默认参数 >>>add_end() ['End','End'] ''' Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容, 则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。 ''' # 修改上面函数使之正常 def add_end(L=None): if L is None: L = [] L.append('End'] return L
可变参数,我更喜欢叫他为元组参数
# 用于接收不确定会接收多少参数时使用 def message(name, age, *args): print(name, age, args) # 不带args调用时,会返回一个() >>>message('Demo', '18') Demo 18 () # 传入多个信息,会将信息传成元组 >>>message('Demo', '18', 'red', 180) Demo 18 ('red', 180)
关键字参数,我更喜欢叫他为字典参数
# 同上面一样,也接收多个参数,不过这个是以字典形式返回,并且需要加上key def message(name, age ,**kwargs): print(name, age, kwargs) # 不带kwargs调用时,会返回一个{} >>>message('Demo', '18') Demo 18 {} # 传入多个信息,会将信息传成字典 >>>message('Demo', 18, sex = 'Male', color = 'Red') Demo 18 {'sex': 'Male', 'color': 'Red'}
变量作用域(从上往下查找顺序)
L 局部作用域
E 必报函数外的函数中
G 全局作用域
B 内建作用域
嵌套函数
name = 'Demo' def change_name(): name2 = 'Demo2' def change_name2(): name3 = 'Demo3' print(name) change_name2() print(name) change_name() # 打印的name顺序为 Demo3 Demo2 该函数既考察了作用域和函数调用顺序
递归函数
# 如果一个函数在内部调用自身本身,这个函数就是递归函数,做个1x2x3x4..... def fact(n) if n =1: return 1 return n*fact(n-1) ''' 查看fact(5)的计算过程 ===> fact(5) ===> 5 * fact(4) ===> 5 * (4 * fact(3)) ===> 5 * (4 * (3 * fact(2))) ===> 5 * (4 * (3 * (2 * fact(1)))) ===> 5 * (4 * (3 * (2 * 1))) ===> 5 * (4 * (3 * 2)) ===> 5 * (4 * 6) ===> 5 * 24 ===> 120 '''
尾递归
# 尾递归是把递归做优化,但是在python中即使做了优化,也会和递归一样出现栈溢出情况 def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num - 1, num * product) ''' return fact_iter(num - 1, num * product)仅返回递归函数本身,num - 1和num * product在函数调用前就会被计算,不影响函数调用。 fact(5)对应的fact_iter(5, 1)的调用如下: ===> fact_iter(5, 1) ===> fact_iter(4, 5) ===> fact_iter(3, 20) ===> fact_iter(2, 60) ===> fact_iter(1, 120) ===> 120 '''
使用递归函数做一个二分查找
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("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid]) return binary_search(dataset[0:mid], find_num) else:# 找的数在mid右面 print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid]) return binary_search(dataset[mid+1:],find_num) else: if dataset[0] == find_num: #find it print("找到数字啦",dataset[0]) else: print("没的分了,要找的数字[%s]不在列表里" % find_num) binary_search(data,66)
匿名函数
# 匿名函数就是不需要显式的指定函数 使用lambda # 普通代码 def calc(n): return n**n print(calc(10)) # 匿名函数 calc = lambda n:n**n # 匿名函数主要是和其他函数搭配使用,如下 res = map(lambda x:x**2,[1,5,7,4,8]) for i in res: print(i)