1.函数描述
# ### 函数 """ (1)函数的定义: 功能 (包裹一部分代码 实现某一个功能 达成某一个目的) (2)函数特点: 可以反复调用,提高代码的复用性,提高开发效率,便于维护管理 """ # (3) 函数的基本格式 """ # 函数的定义处 def func(): code1.... code2.... # 函数的调用处 func() """ # 函数的定义处 def func(): print("今天是好日子") # 函数的调用处 func() # (4) 函数的命名 """ 函数的命名 字母数字下划线,首字符不能位数字 严格区分大小且,且不能使用关键字 函数命名有意义,且不能使用中文哦 驼峰命名法: (1)大驼峰命名法:每个单词的首字符大写 (一般在类中起名用这样的方式, 推荐) mycar => MyCar busstop => BusStop myhouse => MyHouse youcanyouupnocannobb => YouCanYouUpNoCanNoBb (2)小驼峰命名法:除了第一个单词首字符不用大写之外,剩下首字符都大写 (函数中的命名) mycar => myCar myhouse=>myHouse mycar => my_car myhouse => my_house (推荐) """ # 函数的定义处 def cheng_fa_biao_99(): for i in range(9,0,-1): for j in range(1,i+1): print("{:d}*{:d}={:2d} ".format(i,j,i*j),end="") print() # 函数的调用处 # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() # cheng_fa_biao_99() for i in range(10): cheng_fa_biao_99()
2.函数参数
# ### 函数的参数 : 函数运算时,需要的值 """ 参数: 形参: 形式参数 (在函数的定义处) 实参: 实际参数 (在函数的调用处) 形参:(普通[位置]形参 , 默认形参 , 普通收集参数 , 命名关键字参数, 关键字收集参数) 实参:(普通实参.关键字实参) 形参 和 实参 要一一对应 """ # (1) 普通形参 # 函数的定义处 hang,lie 普通形参 def small_start(hang,lie): i = 0 while i<hang: j = 0 while j<lie: # 打印星星 print("*",end="") j+=1 # 打印换行 print() i+=1 # 函数的调用处 3,8 普通实参 small_start(3,8) # (2) 默认形参 hang,lie 在函数定义处给与默认值 """ 如果给与实参,那么就使用实际参数, 如果没给实参,那么就使用参数的默认值 """ def small_start(hang=10,lie=10): i = 0 while i<hang: j = 0 while j<lie: # 打印星星 print("*",end="") j+=1 # 打印换行 print() i+=1 # small_start() small_start(4,9) # (3) 普通形参 + 默认形参 """默认形参必须写在普通形参的后面,语法上有要求""" # 函数的定义处 def small_start(hang,lie=10): # def small_start(hang,lie=10): i = 0 while i<hang: j = 0 while j<lie: # 打印星星 print("*",end="") j+=1 # 打印换行 print() i+=1 # 函数的调用处 # small_start(3) # small_start(4,8) # small_start() error # 形参实参要一一匹配 # (4) 关键字实参 """ (1)如果使用关键字实参进行函数调用,实参的顺序无所谓 """ """ (2)如果定义时是普通形参,调用时是关键字实参, 那么这个参数后面的所有调用方式都需要关键字实参进行调用 """ def small_start(hang,a,b,c,lie=10): # def small_start(hang,lie=10): i = 0 while i<hang: j = 0 while j<lie: # 打印星星 print("*",end="") j+=1 # 打印换行 print() i+=1 # 关键字实参 hang 和 lie # small_start(lie = 12,hang = 12) # small_start(3,4,5,6,7) small_start(3,c=90,b=7,a=5,lie =14)
3.收集参数
# ### 收集参数 """ 收集参数: (1) 普通收集参数 * 在函数的定义处 专门用来收集那些多余的,没人要的普通实参,形成一个元组 语法:def func(*args) : args => arguments def func(*args): print(args) => 返回的数据类型是元组 """ def func(a,b,c,*args): print(a,b,c) print(args) func(1,2,3,4,5,6,6,7,8,8,8,8,8,9) # 计算任意长度的累加和 def mysum(*args): total = 0 for i in args: total += i print(total) mysum(11,23,45,56,1,2) """ 收集参数: (2) 关键字收集参数 ** 在函数的定义处 专门用来收集那些多余的,没人要的关键字实参,形成一个字典 语法:def func(**kwargs) : kwargs => keyword arguments def func(**kwargs): print(kwargs) => 返回的数据类型是字典 """ def func(a=1,b=2,**kwargs): print(a,b) print(kwargs) # 方法1 func(99,b=99,c=4,d=90,f=78) # 方法2 func(b=99,a=111,c=4,d=90,f=78) # 拼接任意字符串 dictvar = {"monitor"} def func(**kwargs): str1 = "" str2 = "" dictvar = {"monitor":"班长","classflower":"班花"} for k,v in kwargs.items(): print(k,v) if k in dictvar: str1 += dictvar[k]+":"+ v + " " else: str2 += v + " " print(str1) print("吃瓜群众:",str2) func(monitor="舒则会",classflower="郭一萌",eatgua1="黄花",eatgua2="李村海")
5.命名关键词参数
# ### 命名关键字参数 """ (1) def func(a,b,*,参数1,参数2....) 在*后面定义的参数就是命名关键字参数 (2) def func(*args,参数,**kwargs) 夹在普通收集参数和关键字收集参数之间的是命名关键字参数 如果是命名关键字参数,必须使用关键字实参来进行调用赋值 """ # 定义方法1 def func(a,b,*,c,d): print(a,b) print(c,d) func(1,2,c=3,d=4) # 定义方法2 def func(*args,c,**kwargs): print(args) print(c) print(kwargs) func(1,2,3,4,a=1,b=2,c=3) # 定义方法3 def func(a,b,*,c=3): print(a,b) print(c) # func(1,2) func(1,2,c=22) # 区别于默认形参 def func(a,b,c=3): print(a,b) print(c) # 三种方式皆可 func(1,2) func(1,2,c=22) func(1,2,22) # ### * 和 ** 的魔术用法 """ 在函数的定义处:* ** 相当于打包操作 (一个是元组,一个是字典) 在函数的调用处:* ** 相当于解包操作 (把里面的元素一个一个拿出来,当成实参调用赋值了) """ # * def func(a,b,c): print(a,b,c) lst = [1,2,3] func(*lst) # 相当于 func(1,2,3) 把列表里面的每一个元素都单独拿出来当成参数进行函数的调用 # ** print('--------->') def func(a,*,b,c,d): print(a) print(b,c,d) dictvar = {"b":2,"c":3,"d":4} func(1,**dictvar) # 相当于 func(1,b=2,c=3,d=4) 把字典里面的每一个键值对,都拿出来,变成键=值的形式,进行关键字实参赋值操作 # 扩展 # 函数的定义处 def func(a,b,*,c,d): print(a,b) print(c,d) lst = [1,2] dictvar = {"c":3,"d":4} # 函数的调用处 func(*lst,**dictvar) """ 在字典的前面加上一个*号,默认只传递键. 一个*号 后面可以跟str list tuple set dict 常用的一般就是list 二个** 后面可以跟dict 把键值对变成键=值得形式进行函数调用. """ def func(a,b): print(a,b) dictvar = {"c":3,"d":4} func(*"pa") """ 函数的定义处:参数的定义有顺序: 普通形参 -> 默认形参 -> 普通收集参数 -> 命名关键字参数 -> 关键字收集参数 def func(*args,**kwawrgs):这样的形式定义函数,可以接收到所有种类的参数; pass """ # 参数练习: def f1(a, b, c=0, *args, **kw): print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) def f2(a, b, c=0, *, d, **kw): print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw) #(一) # f1(1, 2) # a=1,b=2,c=0,args=(),kw={} # f1(1, 2, c=3) #a=1,b=2,c=3,args=(),kw={} # f1(1, 2, 3, 'a', 'b') # a=1,b=2,c=3,args=(a,b),kw={} # f1(1, 2, 3, 'a', 'b', x=99)#a=1,b=2,c=3,args=(a,b),kw={x:99} # f2(1, 2, d=99, ext=None)#a=1,b=2,c=0,d=99,kw={ext:None} #(二) args = (1, 2, 3, 4) kw = {'d': 99, 'x': '#'} # f1(1,2,3,4,d=99,x="#") f1(*args, **kw) #a=1,b=2,c=3,args=(4,),kw={'d':99,x:'#'} #(三) myargs = (1, 2, 3) mykw = {'d': 88, 'x': '#'} f2(*myargs, **mykw) #a=1,b=2,c=3,d=88,kw={x:'#'} #(四) a b 普通形参 c 默认形参 *args 普通收集参数 d 命名关键字参数 kw 关键字收集参数 def f1(a, b, c=0, *args,d,**kw): print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) print(d) f1(1,2,3, 'a', 'b',d=67, x=99,y=77) #a=1,b=2,c=3,d=67,args=(a,b),kw={,x:99,y:77}
5.return 返回值
# ### return 函数的返回值,只出现在函数里 """ return 自定义返回值,如果没有写return ,默认返回None 功能:把值返回到函数的调用处; (1)return 后面可以返回值 是自定义的. 除了6大标准数据类型之外,还有类 对象 函数 (2)如果执行了return 语句,意味着函数终止,后面的代码不执行 """ # (1) return 后面可以返回值 是自定义的. 除了6大标准数据类型之外,还有类 对象 函数 def func(): # return 1 # return 3.14 # return 3+4j # return True # return [1,2,3] # return {"a":1,"b":2} pass res = func() # res ={"a":1,"b":2} print(res) res = print(1) print(res) # (2) 如果执行了return 语句,意味着函数终止,后面的代码不执行 def func(): print("这句话执行了1") print("这句话执行了2") return 1 print("这句话执行了3") print("这句话执行了4") res = func() print(res) print("<============>") def func(): for i in range(5): if i == 3: return i print(i) res = func() # 0 1 2 # (3) 计算器小例子 def calc(sign,num1,num2): if sign == "+": res = num1 + num2 elif sign == "-": res = num1 - num2 elif sign == "*": res = num1 * num2 elif sign == "/": if num2 == 0: return "除数不能为0" res = num1 / num2 return res print("<===>") res = calc("+",1,1) res = calc("-",-1,90) res = calc("*",52,10) res = calc("/",52,10) res = calc("/",5200,10) print(res)
6.函数名的使用
# ### 1.函数名的使用 # 1.函数名是个特殊的变量,可以当做变量赋值 def func(): print("函数名可以当成变量使用") abc = 45 abc = func print(abc) abc() # 2.函数名可以作为容器类型数据的元素 def func1(): print(1) def func2(): print(2) def func3(): print(3) lst = [func1,func2,func3] for i in lst: i() # func1() func2() func3() # 3.函数名可以作为函数的参数 def func1(func): func() def func2(): print('woshi func2') # func形参接收到了func2这个实参函数,调用func1执行里面的代码块.调用func2() func1(func2) print("<===>") # 4.函数名可作为函数的返回值 def func3(func): return func def func4(): print("woshi func4") # func4这个实参被func接收到 ,执行func3代码块内容,直接return func4 ,res接收到了返回值func4 res = func3(func4) res() # func4() # ### 2.__doc__或者help查看文档 # help(print) res = print.__doc__ print(res) # 如何自定义函数的文档 # 吃大肠的过程 def eat_big_chang(something): """ 功能:模拟吃大肠的过程 参数:大肠 返回值:吃没吃完的状态 """ print("我是在模拟{}过程".format(something)) print("第一步.找肠子头") print("第二步.把肠子头放嘴里") print("第三步.使劲唆") return "擦擦嘴,满意的放下肠子.吃完了" eat_big_chang("吃大肠") # 方法1 用 函数.__doc__ res = eat_big_chang.__doc__ print(res) # 方法2 print("<===>") help(eat_big_chang)
7.全局变量与局部变量
# ### 全局变量 与 局部变量 """ 局部变量:定义在函数内部的变量 全局变量:定义在函数外部或者用global关键字在函数内部定义的变量 作用域: 作用的范围 局部变量的作用域:只限定在函数内部; 全局变量的作用域:横跨整个文件 """ # 1.局部变量的获取 与 修改 def func(): a = 15 # 获取局部变量 print(a) # 修改局部变量 a = 17 print(a) func() # print(a) error a局部变量值限定在函数内部使用; # 2.全局变量的获取 与 修改 b = 100 # 获取全局变量 print(b) # 修改全局变量 b += 200 print(b) print("<====>") # 3.在函数内部可以直接获取全局变量,但是不能直接修改 # 用global关键字,修改全局变量 c = 50 def func(): global c print(c) c = 60 print(c) func() print(c) # 4.在函数内部可以直接定义一个全局变量 def func(): global d d = 90 func() print(d) # 总结: """ global关键字 如果函数外部没有该变量,就是在函数内部定义一个全局变量 global关键字 如果函数外部有该变量,那么就是在函数内部修改一个全局变量 global用来修饰全局变量 ; 有就修改,没有就创建. """
8.函数的嵌套
# ### 函数的嵌套 """ 函数之间允许嵌套: 嵌套在外层的就是外函数 嵌套在内容的就是内函数 """ def outer(): def inner(): print("111") inner() """ (1)内部函数可以直接在函数外部调用么 不行 (2)调用外部函数后,内部函数可以在函数外部调用吗 不行 (3)内部函数可以在函数内部调用吗 可以 (4)内部函数在函数内部调用时,是否有先后顺序 在定义在调用 python 没有预加载机制:即不能提前把函数加载到内存当中. """ outer() """ def func(): pass func() int a = 5 c int a = 6 java $a = 67 php var a = 89 js a = 90 python """ # 外层是outer函数,里面有inner , inner 中还有smaller ,如果调用smaller? def outer(): def inner(): def smaller(): print(id) print("我是smaller函数") smaller() inner() outer() # LEGB 原则 (就近找变量原则) """ #找寻变量的调用顺序采用LEGB原则(即就近原则) B —— Builtin(Python);Python内置模块的命名空间 (内建作用域) G —— Global(module); 函数外部所在的命名空间 (全局作用域) E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域) L —— Local(function);当前函数内的作用域 (局部作用域) 依据就近原则,从下往上 从里向外 依次寻找 """ # 生命周期 """ 内置命名空间中的所有变量 > 全局命名空间中的所有变量 > 局部命名空间中的所有变量 """ # 了解 """ # 命名空间 : 划分一块区域保存所有数据,以字典的方式存储(变量与值形成映射关系).一共三种. (1)内建命名空间:解释器启动时创建,直到解释器运行结束,生存周期最长 (2)全局命名空间:文件运行时创建,直到解释器运行结束,生存周期较长 (3)局部命名空间:函数调用时,里面的局部变量才创建,调用结束后即释放,生存周期较短 #命名空间的提出是为了划分和控制变量是否可见,以及生存周期的长短. #命名空间 创建顺序:(了解) python解释器启动->创建内建命名空间->创建全局命名空间->创建局部命名空间 #命名空间 销毁顺序:(了解) 函数调用结束后->销毁函数对应的局部命名空间数据->销毁全局命名空间数据->销毁内建命名空间数据 """ """ # 地址相关知识点: -5~正无穷 int 浮点型非负数 float 相同的布尔值 bool 在实数+虚数结构中永远不相同(只有虚数部分除外) complex 相同的字符串 str 空元组 tuple id() 用来获取地址 is / is not 针对于地址提出来,用来判断两个变量地址是否相同. var1 = 90 var2 = 90 print(id(var1)) print(id(var2)) """
9.nonlocal
# ### nonlocal 用来修饰局部变量 """ nonlocal 符合LEGB 原则, 就近原则找变量; (1) nonlocal 用来修改局部变量 (2) nonlocal 会不停的寻找上一层空间所对应的值,拿来修改 (3) 如果上一层找不到,继续向上寻找,再也找不到了,直接报错; """ # (1) nonlocal 只能用来修改局部变量 a = 90 def func(): # nonlocal a error a = 80 print(a) func() # (2) nonlocal 会不停的寻找上一层空间所对应的值,拿来修改 """通过LEGB原则,可以获取到上一层空间的值,只能单纯的获取,不能直接修改 如果想要修改 通过nonlocal 加以修饰. """ def outer(): a = 20 def inner(): nonlocal a print(a) a += 1 print(a) inner() outer() # (3) 如果上一层找不到,继续向上寻找,再也找不到了,直接报错; nonlocal 只能修饰局部变量 a = 100 def outer(): a = 100 def inner(): # a = 110 def smaller(): nonlocal a a += 10 # print(a) smaller() print(a,"<=1=>") inner() print(a,"<=2=>") outer() # (4) 不通过nonlocal 是否可以改变局部变量? 可以! 需要使用列表进行操作; def outer(): lst = [100,101,102] def inner(): lst[0] += 1 inner() print(lst) outer()
10.闭包函数
# ### 闭包函数 """ 概念:内函数使用了外函数的局部变量, 并且外函数把内函数返回出来的过程,叫做闭包 这个内函数叫做闭包函数 """ # (1) 基本语法: def lizuqing_family(): father = "李嘉诚" def father_say(): print("{}说了:先定他一个小目标,买一个英国伦敦".format(father)) return father_say func = lizuqing_family() # func = father_say print(func) func() #=> father_say() # (2) 闭包函数的升级 """ 内函数使用了外函数的局部变量,外函数的局部变量与内函数发生绑定,延长了该变量的生命周期 """ def liaopingping_family(): jiejie = "马蓉" meimei = "马诺" money = 1000 def jiejie_hobby(): nonlocal money money -= 500 print("买名牌包包,名牌手表,名牌狗链,.....家里的前还剩下%s"%(money)) def meimei_hobby(): nonlocal money money -= 400 print("宁愿在宝马里面哭,也不愿再自行车上面撒欢.家里的钱还剩下%s"%(money)) def big_guanjia(): return jiejie_hobby,meimei_hobby # 返回一个元组 # return (jiejie_hobby,meimei_hobby) return big_guanjia func = liaopingping_family() print(func) tup = func() print(tup) #(<function liaopingping_family.<locals>.jiejie_hobby at 0x000001DCD2877048>, <function liaopingping_family.<locals>.meimei_hobby at 0x000001DCD28770D0>) # 调用 姐姐jiejie_hobby jiejie = tup[0] print(jiejie) #<function liaopingping_family.<locals>.jiejie_hobby at 0x0000026526B49048> jiejie() # 调用 妹妹meimei_hobby meimei = tup[1] meimei() # <function liaopingping_family.<locals>.meimei_hobby at 0x000001DCD28770D0>
11.闭包的特点
# ### 闭包的特点 """ 内函数使用了外函数的局部变量,外函数的局部变量与内函数发生绑定,延长了该变量的生命周期 """ def outer(val): def inner(num): return num + val return inner func = outer(10) res = func(5) # func = inner() = num + val = 10 + 5 = 15 print(res) """ func = outer(10) val 接收到10这个值 return inner 因为内函数使用了外函数的局部变量val,val就与内函数发生绑定,延长该变量生命周期,不释放,等待下一次调用时使用 res = func(5) num 接受到5这个值 return num + val return 5 + 10 => return 15 """ # ### 闭包的意义 """ 闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装保护的作用.外部无法访问. 模拟一个鼠标点击计数功能: """ clicknum = 0 def clickfunc(): global clicknum clicknum += 1 print(clicknum) # 模拟点击操作,点击一次就调用一次 clickfunc() clickfunc() clickfunc() clickfunc() clickfunc() clicknum = 100 clickfunc() # 用闭包函数来进行改造 def clickfunc(): x = 0 def func(): nonlocal x x +=1 print(x) return func clickfunc2 = clickfunc() clickfunc2() # clickfunc2() = func() clickfunc2() clickfunc2() clickfunc2() clickfunc2() x = 100 clickfunc2()
12.locals和globals
# ### locals 和 globals """ locals() 获取当前作用域的所有变量 如果locals在函数外:所获取的是locals(),打印返回值之前的所有内容 如果locals在函数内:所获取的是locals(),调用之前所有内容 """ # 当前作用域在全局范围 a = 1 b = 2 res = locals() c = 3 print(res) """ # 当前作用域在局部范围 zz = 90 def func(): d = 4 f = 5 res = locals() g = 6 print(res) func() """ """ globals 无论在函数内外,都只获取全局作用域当中的所有内容 如果globals在函数外:所获取的是globals(),打印返回值之前的所有内容 如果globals在函数内:所获取的是globals(),调用之前所有内容 """ # 当前作用域在全局范围 a = 1 b = 2 res = globals() c = 3 print(res) # 当前作用域在局部范围 ''' aa = 11 bb = 22 def func(): d =1 f = 2 res = globals() z = 3 print(res) cc = 33 func() #res = globals() dd = 4 ''' # globals 动态的创建全局变量 """ globals() 返回的是系统的字典,只需要在字典里面添加键值对,就可以创建全局变量 字典中的键 就是变量名 字典中的值 就是变量所指代的值 """ dic = globals() print(dic) dic["wangwen"] = "风流倜傥,美若天仙,才华横溢,玉树临风" # wangwen = "风流倜傥,美若天仙,才华横溢,玉树临风" print(wangwen) # globals 批量创建全局变量 # 创建p1~p5 5个全局变量 def func(): dic = globals() for i in range(1,6): # p1 ~ p5 5个键 dic["p%d" % (i)] = i func() print(p1) print(p2) print(p3) print(p4) print(p5)
13.匿名函数
# ### 匿名函数 => lambda 表达式 """ lambda 表达式: 用一句话来表达只有返回值的函数 好处: 简洁,方便,定义函数快速简单 语法: lambda 参数 : 返回值 """ # 1.无参的lambda表达式 def func(): return 123456 func = lambda : 123456 res = func() print(res) # 2.有参的lambda表达式 def func(n): return type(n) res = func("1234") print(res) func = lambda n : type(n) res = func([1,2,3]) print(res) # 3.带有条件判断的lambda表达式 def func(n): if n % 2 == 0: return "偶数" else: return "奇数" # 4.三目运算符: 用来表达双项分支 """ 真值 if 条件表达式 else 假值 如果条件表达式成立,执行真值 如果条件表达式不成立,执行假值 """ n = 11 res = "偶数" if n % 2 == 0 else "奇数" print(res) n = 90 func = lambda n : "偶数" if n % 2 == 0 else "奇数" print( func(n) ) # 计算参数中的最大值 def func(m,n): if m>n: return m else: return n print( func(13,9) ) func = lambda m,n : m if m>n else n print( func(-90,90) )
14.递归函数
# ### 递归函数 """ 递归函数:自己调用自己的函数 递:去 归:回 一去一回是递归 递归的最大深度:官网说法1000层,但实际996~1000 """ # 简单递归 def digui(n): print(n,"<==11==>") if n>0: digui(n-1) print(n,"<==22==>") digui(5) """ 去的过程: n = 5 print(5,"<==11==>") 5 > 0 digui(5 - 1) digui(4) n = 4 print(4,"<==11==>") 4 > 0 digui(4 - 1) digui(3) n = 3 print(3,"<==11==>") 3 > 0 digui(3 - 1) digui(2) n = 2 print(2,"<==11==>") 2 > 0 digui(2 - 1) digui(1) n = 1 print(1,"<==11==>") 1 > 0 digui(1 - 1) digui(0) n = 0 print(0,"<==11==>") 0 > 0 条件不满足,往下执行 print(0,"<==22==>") 回的过程: (把剩下的没走玩的代码继续执行) 回到上一次函数的调用处第17行,从17行继续向下执行 n = 1 print(1,"<==22==>") 回到上一次函数的调用处第17行,从17行继续向下执行 n = 2 print(2,"<==22==>") 回到上一次函数的调用处第17行,从17行继续向下执行 n = 3 print(3,"<==22==>") 回到上一次函数的调用处第17行,从17行继续向下执行 n = 4 print(4,"<==22==>") 回到上一次函数的调用处第17行,从17行继续向下执行 n = 5 print(5,"<==22==>") 递归函数彻底终止. """ """ # 递归的最大深度 error def func(): func() #[Previous line repeated 995 more times] func() """ # 栈帧空间:是为了运行函数所需要开辟的空间 """ (1)没调用一次函数,就是开辟一个栈帧空间的过程 每结束一次函数,就是释放一个栈帧空间的过程 递归函数就是不停的开辟栈帧空间和释放栈帧空间的过程 (2)回的过程有两种触发时机: (1)当最后一层函数全部执行完毕,触发回的过程,回到上一层函数调用处 (2)当遇到return 返回值的时候,触发回的过程,回到上一层函数调用处 (3)如果递归层数过大,不推荐使用递归,如果使用,务必添加一个跳出的条件,防止内存溢出; """ """ # 栈帧空间彼此的数据是隔离的,彼此独立,各是各的空间 def abc(n) print(n) abc(1) abc(2) """ # 计算n的阶乘 5! = 5*4*3*2*1 def jiecheng(n): if n<=1: return 1 return n * jiecheng(n-1) res = jiecheng(5) print(res) """ 需要先把表达式的值算完之后,再返回 # 去的过程 n = 5 return 5 * jiecheng(5 - 1) => 5 * jiecheng(4) n = 4 return 4 * jiecheng(4 - 1) => 4 * jiecheng(3) n = 3 return 3 * jiecheng(3 - 1) => 3 * jiecheng(2) n = 2 return 2 * jiecheng(2 - 1) => 2 * jiecheng(1) n = 1 n <= 1 满足 return 1 # 回的过程 n = 2 return 2 * jiecheng(2 - 1) => 2 * jiecheng(1) => 2 * 1 n = 3 return 3 * jiecheng(3 - 1) => 3 * jiecheng(2) => 3 * 2 * 1 n = 4 return 4 * jiecheng(4 - 1) => 4 * jiecheng(3) => 4 * 3 * 2 * 1 n = 5 return 5 * jiecheng(5 - 1) => 5 * jiecheng(4) => 5 * 4 * 3 * 2 * 1 最后直接 return 5 * 4 * 3 * 2 * 1 = 120 """ print(jiecheng(1))