Python尾递归-创始人为何不愿TRE以及我们如何模拟TRE
TRE=Tail Recursion Elimination
创始人是不愿意实现TRE的.他专门用了一篇文章来阐述原因.
http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html
1.不利于查BUG.
2.现有的1000递归深度够用.
3.递归不是所有编程的基础,也不是一个日常工具.
4.他举了个例子说明第四点,大概是指Python动态的特性不适合递归:
def f(x):
print 'original'
if x > 0:
return f(x-1)
return 0
g = f
def f(x):
print 'new'
return x
print g(5)
最终结果是4:
original
new
4
最后总结:
After all TRE only addresses recursion that can easily be replaced by a loop.
意思应该是说所有真正需要TRE的地方都能轻松改写为循环.
看来我是不能指望Python语言支持TRE了.
但还是有很多顽强的程序员用各种方法变相支持TRE.比如下面这位还用装饰器的形式实现了.
http://web.mit.edu/kmill/www/programming/tailcall.html
class TailCaller(object) :
def __init__(self, f) :
self.f = f
def __call__(self, *args, **kwargs) :
ret = self.f(*args, **kwargs)
while type(ret) is TailCall :
ret = ret.handle()
return ret class TailCall(object) :
def __init__(self, call, *args, **kwargs) :
self.call = call
self.args = args
self.kwargs = kwargs
def handle(self) :
if type(self.call) is TailCaller :
return self.call.f(*self.args, **self.kwargs)
else :
return self.f(*self.args, **self.kwargs) @TailCaller
def fact(n, r=1) :
if n <= 1 :
return r
else :
return TailCall(fact, n-1, n*r) print fact(2500)
最朴素的形式是:
def TCO(f):
def inner(*nkw,**kw):
result=f(*nkw,**kw)
while callable(result):
result=result()
return result
return inner def fab(n,s=1):
if n<2:
return s
else:
return lambda :fab(n-1,s*n) tcoFab=TCO(fab)
print tcoFab(2500)
这个更容易理解,性能也应该会更好,只是行文略显复杂了一点点.主要是由于Python运行时的动态特性,你不能使用更酷的装饰器形式fab=TCO(fab).
我个人是比较支持这种朴素形式的.
网上还有其他一些什么抛出异常法之类的,用到了sys模块,太复杂了,看不懂,故不用.
Python尾递归-创始人为何不愿TRE以及我们如何模拟TRE的更多相关文章
- Python用上锁和解锁 lock lock.acquire lock.release 模拟抢火车票
Python用上锁和解锁 lock lock.acquire lock.release 模拟抢火车票 import jsonimport timefrom multiprocessing impor ...
- 孤荷凌寒自学python第八十五天配置selenium并进行模拟浏览器操作1
孤荷凌寒自学python第八十五天配置selenium并进行模拟浏览器操作1 (完整学习过程屏幕记录视频地址在文末) 要模拟进行浏览器操作,只用requests是不行的,因此今天了解到有专门的解决方案 ...
- Python尾递归优化
Python开启尾递归优化 cpython本身不支持尾递归优化, 但是一个牛人想出的解决办法:实现一个 tail_call_optimized 装饰器 #!/usr/bin/env python2.4 ...
- Python尾递归-求斐波那契数列
# coding=utf-8 # Fibonacci.py Fib = {} def Fibonacci(n): global Fib if Fib.has_key(n): return Fib[n] ...
- Python脚本控制的WebDriver 常用操作 <十二> send_keys模拟按键输入
下面将使用WebDriver中的send_keys来模拟键盘按键输入 测试用例场景 send_keys方法可以模拟一些组合键操作: ctrl+a ctrl+c ctrl+v 等. 另外有时候我们需要在 ...
- Python爬虫入门教程 49-100 Appium安装+操作51JOB_APP(模拟手机操作之一)手机APP爬虫
爬前准备工作 在开始安装Appium之前,你要先知道Appium是做什么的?Appium 是一个自动化测试开源工具,看到没,做测试用的,它有点类似Selenium,可以自动操作APP实现一系列的操作. ...
- Python爬虫学习==>第十二章:使用 Selenium 模拟浏览器抓取淘宝商品美食信息
学习目的: selenium目前版本已经到了3代目,你想加薪,就跟面试官扯这个,你赢了,工资就到位了,加上一个脚本的应用,结局你懂的 正式步骤 需求背景:抓取淘宝美食 Step1:流程分析 搜索关键字 ...
- Python基础(二):斐波那契数列、模拟cp操作、生成8位随机密码
一.斐波那契数列 目标: 编写fib.py脚本,主要要求如下: 输出具有10个数字的斐波那契数列 使用for循环和range函数完成 改进程序,要求用户输入一个数字,可以生成用户需要长度的斐波那契数列 ...
- Python day15装饰器基本理论,以及结合全局变量模拟session
装饰器(decorator):为其他函数添加附加功能 原则:1.不修改被修饰函数源代码 2.不修改被修饰函数的调用方式 装饰器=高阶函数+函数嵌套+闭包 import time def timmer( ...
随机推荐
- Java 异常基础详解
目录 1. Java 中的异常 1.1 什么是异常? 1.2 什么是异常处理? 1.2.1 异常处理的优势 1.3 Java 异常类的层次结构 1.4 异常类型 1.5 检查和未检查异常之间的区别 1 ...
- MySQL加载本地数据时出现1290(HY000)错误
- Mysql之基本操作与数据类型
进入mysql: mysql -hlocalhost -uroot -p; mysql -uroot -p密码; 查看帮助文档: help 查看名 database(s); 创建数据库: create ...
- Docker入门之---ENTRYPOINT和CMD
1. 前言 ENTRYPOINT 和CMD 都是Dockerfile 中的命令,两者都是用来:指定默认的容器的主进程的启动命令.那么接下来就介绍一下这两者在Dockerfile 中,以及Docker ...
- HNOI2018 滚粗记
day0 说好了不复习,于是复习了一下配置,没想到一下就记住了,咋不退役去搞英语竞赛捏 皇室一波攒RP,chicken chicken一波攒RP day1 机子坏了,换到了最后面,但这个时候已经 \( ...
- ●SPOJ LCS2Longest Common Substring II
题链: http://www.spoj.com/problems/LCS2/题解: 后缀自动机. 对第一个串建立后缀自动机, 然后把后面的每个串分别与该串的自动机去匹配,求出相应的数组val*[s]: ...
- ●POJ 2007 Scrambled Polygon
题链: http://poj.org/problem?id=2007 题解: 计算几何,极角排序 按样例来说,应该就是要把凸包上的i点按 第三像限-第四像限-第一像限-第二像限 的顺序输出. 按 叉积 ...
- web框架和django基础(粗糙版)
web框架本质: 浏览器:socket客户端 服务器:socket服务端 1.自己写socket服务端(最傻) #!/usr/bin/env python ...
- 遗传算法:N皇后
N皇后问题描述 N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 遗传算法 遗传算法是局部束搜索的变形: 与自 ...
- Cisco banner 登陆消息提示设置命令详解
从法律角度来看,登陆消息非常重要.当入侵者进入网络而没有受到适当的警告时,他们有可能赢得官司.在放置登陆消息之前应让律师检查下,永远不要使用"欢迎"等问候语,以免被误解为邀请大家使 ...