函数执行流程、递归函数、匿名函数

标签: python
10人阅读 评论(0) 收藏 举报
分类:

函数执行流程

示范代码

def foo1(b,b1=3):
    print("foo1 called",b,b1)
def foo2(c):
    foo3(c)
    print("foo2 called",c)
def foo3(d):
    print("foo3 called",d)
def main():
    print("main called")
    foo1(100,101)
    foo2(200)
    print("main ending")

示范代码执行流程

执行流程

  1. 全局帧中生成foo1、foo2、foo3、main函数对象
  2. main函数调用
  3. main中查找内建函数print压栈,将常量字符串压栈,调用函数,弹出栈顶
  4. main中全局查找函数foo1压栈,将常量100、101压栈,调用函数foo1,创建栈帧。print函数压栈,字符串和变量b、b1压栈,调用函数,弹出栈顶,返回值
  5. main中全局查找foo2函数压栈,将常量200压栈,调用foo2,创建栈帧。foo3函数压栈,变量c引用压栈,调用foo3,创建栈帧。foo3完成print函数调用后返回,返回值。main中foo2调用结束后弹出栈顶,main继续执行print函数调用,弹出栈顶。main函数返回。

示范代码

import dis
def foo1(b,b1=3):
    print("foo1 called",b,b1)
    foo2(2)
def foo2(a):
    pass
print(dis.dis(foo1))

代码字节码

[python@centos7 416]$./foo.py 
  6           0 LOAD_GLOBAL              0 (print)
              3 LOAD_CONST               1 ('foo1 called')
              6 LOAD_FAST                0 (b)
              9 LOAD_FAST                1 (b1)
             12 CALL_FUNCTION            3 (3 positional, 0 keyword pair)
             15 POP_TOP

  7          16 LOAD_GLOBAL              1 (foo2)
             19 LOAD_CONST               2 (2)
             22 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             25 POP_TOP
             26 LOAD_CONST               0 (None)
             29 RETURN_VALUE
None

递归函数

递归函数含义

  • 函数直接或间接调用自身就是递归
  • 递归需要有边界条件、递归前进段、递归返回段
  • 递归一定要有边界条件
  • 当边界条件不满足得实惠,递归前进
  • 当边界条件满足的时候,递归返回

递归性能

  • 循环稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果
  • fib函数代码极简易懂,但是只能获得最外层的函数调用,内部递归结果都是中间结果,而且给定一个n都要进行近2n次递归,深度越深,效率越低,为了获取斐波那契数列需要外面在套一个n次的循环,效率更低了
  • 递归还有深度限制,如果递归复杂,函数反复压栈,栈内存很快就溢出了

递归优化

解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以把循环看成是一种特殊的尾递归函数也是可以的,尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包涵表达式。这样编译器或者解释器就可以把尾递归优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况

递归函数总结

  • 递归是一种很自然的表达,符合逻辑思维
  • 递归相对运行效率低,每一次调用函数都要开辟栈帧
  • 递归有深度限制,如果递归层次太深,函数反复压栈,内存很快就溢出
  • 如果是有限次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果
  • 绝大多数递归,都可以使用循环实现
  • 即使递归代码很简洁,但是能不用则不用递归

求斐波那契数列

斐波那契数列解法1

  • 重点内容是f(n)=f(n-1)+f(n-2),因此得出函数为
#!/home/python/.pyenv/versions/3.5.3/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-16
def f(n):
    return 1 if n < 3 else f(n-1)+f(n-2)
for i in range(1,11):
    print(f(i),end=" ")
print()
运行结果:
[python@centos7 416]$./recusion.py 
1 1 2 3 5 8 13 21 34 55 
  • 利用for循环将正序输出斐波那契数列公式

斐波那契数列解法2

#!/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-16
def f(n,x=[1],y=[0]):
    if n > 1:
        x[0],y[0] = x[0]+y[0],x[0]
        print(y[0],end=" ")
    else:
        return x[0]
    return f(n-1,x=[x[0]],y=[y[0]])
print(f(10))
运行结果:
[python@centos7 416]$./recusion.py 
1 1 2 3 5 8 13 21 34 55 
  • 利用函数默认值属性
  • 利用函数体就是关系式,return就是返回结果进行计算

斐波那契数列解法3

#!/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-16
def fib(n,cur=1,pre=0):
    if n > 1:
        cur,pre = cur+pre,cur
        print(pre,end=" ")
    else:
        return cur
    return fib(n-1,cur,pre) #通过位置变量传参
print(fib(10))

求n的阶乘

传统解法

#!/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-16
def f(n):
    if n == 1:
        return 1 
    return n*f(n-1)
print(f(5))
运行结果:
[python@centos7 416]$./fact.py 
120

for循环思路解法

#!/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-15
import dis
def f(n,s=[1]):
    if n ==1:
        print(s[0])          #顶层栈帧pop时,s[0]的值120
        return 
    s[0] *= n
    f(n-1,s=[s[0]])
    return s[0]              #此时最底层栈帧时,s[0]的值为5
print(f(5))
运行结果:
[python@centos7 414]$./n.py 
120
None
  • 此案例能够帮助更深层次理解

尾递归法

#!/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-16
def f(n,num=1):
    if n == 1:
        return num
    num *= n
    return f(n-1,num)    #每次重新创建新的栈,而且这个栈就调用一次即可
print(f(5))
运行结果:
120

序列逆放

将一个数逆序放入列表中,如:1234=>[4,3,2,1]

#!/bin/python3
#-*- coding: UTF-8 -*-
#created time 2018-04-17
def rever(n,s,l=[]):
    if n == 0:
        return l
    num=divmod(int(s),10)
    l.append(num[1])
    return rever(n-1,num[0])
print(rever(4,1234))
运行结果:
[python@centos7 416]$./lst.py 
[4, 3, 2, 1]
查看评论

--=== 让你的程序开始说话(在VB中使用文字朗读引擎(TTS)技术)===--

在VB中使用文字朗读引擎(TTS)技术(作者:许锦新 2001年04月10日 13:52)  现今市面上流行的一些英语学习软件,在广告词上经常说自己使用了国际顶尖的全程语音TTS技术,能进行整段英文的...
  • coolstar
  • coolstar
  • 2001-05-04 17:29:00
  • 2327

js匿名函数实现递归调用

Document //求阶乘 var a = (function (value) { if (value > 1) return value * arguments.call...
  • z83986976
  • z83986976
  • 2015-07-12 20:28:10
  • 1086

深入理解递归函数的调用过程

下面是个关于递归调用简单但是很能说明问题的例子:/*递归例子*/#includevoid up_and_down(int);int main(void){   up_and_down(1);...
  • ysuncn
  • ysuncn
  • 2007-09-21 02:09:00
  • 9135

java中递归函数的调用

java中递归函数的调用-求一个数的阶乘 不考虑溢出:一般只能算到69的阶乘…… 注意:0的阶乘0!=1 任何大于1的自然数n阶乘表示方法: n!=1×2×3×……×n ...
  • zhengqiqiqinqin
  • zhengqiqiqinqin
  • 2013-06-08 22:37:08
  • 8065

lua函数递归

我们先从一个错误的实例开始我们的讨论 local fact = function (n) if n == 0 then return 1 else return n*fact(n...
  • youchengyuanzhi
  • youchengyuanzhi
  • 2014-02-21 17:15:46
  • 701

具名函数和匿名函数

废话不说,先上代码 具名函数 var a = 2; function foo() { var a = 3; console.log( a ); //3 } foo(); console.log( ...
  • Efficiency9
  • Efficiency9
  • 2017-06-30 21:34:17
  • 482

Java中函数的递归调用

说到递归,java中的递归和C语言中也是很相似的,在Java中,递归其实就是利用了栈的先进后出的机制来描述的。public class HelloWorld { public static void...
  • morixinguan
  • morixinguan
  • 2016-08-17 13:58:20
  • 1615

C++11:匿名函数(lambda函数/表达式)及其用法

C++11:匿名函数(lambda函数/表达式)及其用法C++11提供了对匿名函数的支持,称为Lambda函数(也叫Lambda表达式). Lambda表达式具体形式如下:[capture](para...
  • stary_yan
  • stary_yan
  • 2016-05-03 23:37:36
  • 817

【转载】MATLAB函数句柄和匿名函数

转自:http://bbs.seu.edu.cn/pc/pccon.php?id=950&nid=14857 下面代码创建一个内联函数a_humps: >> a_humps = inline(...
  • lqzdreamer
  • lqzdreamer
  • 2017-04-19 10:24:19
  • 645

匿名函数(Lambda表达式)与箭头函数

“Lambda 表达式”(lambda expression)是匿名函数的别称。 在ES6中,允许使用箭头=>定义匿名函数。var f = v => v;上面的箭头函数等同于:var f = fun...
  • maomaolaoshi
  • maomaolaoshi
  • 2017-10-26 16:57:09
  • 732
    个人资料
    持之以恒
    等级:
    访问量: 493
    积分: 321
    排名: 25万+
    文章分类
    文章存档
    最新评论