我们围绕一个数学问题来说明本文的思想,组合数C(n,i),也就是从n个元素中任选i个,共有多少种选法。当然,这个问题有很多种求解方法,例如最快的组合数算法之Python实现。本文主要分析组合数的递归求解方法,也就是著名的帕斯卡公式C(n,i) = C(n-1, i) + C(n-1, i-1),首先编写出可以运行的正确代码,然后再进行优化和改进。

import time

from functools import wraps

def f0(n, i):

'''原始版本,随着参数的增大很快就会崩溃'''

if n==i or i==0:

return 1

return f0(n-1, i) + f0(n-1, i-1)

#使用全局的字典来存储中间计算结果,避免重复计算

#并且崩溃会晚一点到来

cache1 = dict()

def f1(n,i):

if n==i or i==0:

return 1

#如果当前参数还没计算过才计算

#如果已经计算过了,就直接返回之前计算的结果

elif (n,i) not in cache1:

cache1[(n,i)] = f(n-1, i) + f(n-1,i-1)

return cache1[(n,i)]

#使用嵌套定义函数来实现同一个问题

def f2(n,i):

cache2 = dict()

def f(n,i):

if n==i or i==0:

return 1

elif (n,i) not in cache2:

cache2[(n,i)] = f(n-1, i) + f(n-1, i-1)

return cache2[(n,i)]

return f(n,i)

#定义修饰器

def cachedFunc(func):

#使用字典存储中间结果

cache = dict()

#对目标函数进行改写

@wraps(func)

def newFunc(*args):

if args not in cache:

cache[args] = func(*args)

return cache[args]

#返回修改过的新函数

return newFunc

#使用修饰器

@cachedFunc

def f3(n, i):

#使用最原始的思路编写代码即可

if n==i or i==0:

return 1

return f3(n-1, i) + f3(n-1, i-1)

#测试不同实现的运行时间

for f in (f0, f1, f2, f3):

start = time.time()

for i in range(100000):

f(15,3)

print(f.__name__, ':', time.time()-start)

运行结果为:

f0 : 19.13409447669983

f1 : 0.04300236701965332

f2 : 4.019229888916016

f3 : 0.03200173377990723

虽然运行效果显示使用修饰器的效果不错,但是大家肯定会有个疑问,是不是针对每个函数都要写一个不同的修饰器呢?实际上是不用的,一般来说,同一个修饰器函数适用于特定的一类问题,是可以重复使用的,例如下面的斐波那契数列问题就重复使用了上面定义的修饰器。

def fib1(i):

if i<2:

return 1

return fib1(i-1) + fib1(i-2)

fib2 = cachedFunc(fib1)

for f in (fib2, fib1):

start = time.time()

for i in range(1000):

f(30)

print(f.__name__, ':', time.time()-start)

运行结果为:

fib1 : 0.4820277690887451

fib1 : 426.09937143325806

太神奇了,居然相差这么多。不过好像有个问题,为啥最后这段代码两次输出的函数名都是fib1呢,第一个为啥不是2呢?这算是修饰器的小坑吧,目前还没有找到解决办法(谁要是知道的话一定要告诉我,谢谢),所以推荐使用修饰器的用法,不建议把修饰器当函数来使用。

最后需要说明的是,本文的思想只是缓解了问题,并不会彻底解决函数递归调用对递归深度的限制,随着参数的增大,一样会崩溃。

针对递归函数的优化与Python修饰器实现相关推荐

  1. python 修饰器 教程_python 实现 修饰器模式

    无论何时我们想对一个对象添加额外的功能,都有下面这些不同的可选方法. 如果合理,可以直接将功能添加到对象所属的类(例如,添加一个新的方法) 使用组合 使用继承 与继承相比,通常应该优先选择组合,因为继 ...

  2. python修饰器_python设计模式之修饰器模式

    python设计模式之修饰器模式 无论何时我们想对一个对象添加额外的功能,都有下面这些不同的可选方法. [ ] 如果合理,可以直接将功能添加到对象所属的类(例如,添加一个新的方法) [ ] 使用组合 ...

  3. Python修饰器的函数式编程

    转载自:https://coolshell.cn/articles/11265.html 加了一些自己的注释. Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其 ...

  4. python修饰器原理_Python修饰器的函数式编程

    Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都 ...

  5. 作为程序员,起码要知道的 Python 修饰器!

    Python修饰器是个非常强大的概念,可以用一个函数去"包装"另一个函数.修饰器的思想,就是把函数中除了正常行为之外的部分抽象出去.这样有很多好处,如很容易进行代码复用,并且能遵守 ...

  6. python 修饰器

    作用 简单的说,python修饰器就是可以对函数的参数以及返回结果进行操作. 如果已经懂了函数闭包的朋友相信已经大概知道该怎么做了,还有不懂的朋友可以看我的这篇文章--python闭包简记. 理解修饰 ...

  7. python装饰器-python修饰器(装饰器)以及wraps

    Python装饰器(decorator)是在程序开发中经常使用到的功能,合理使用装饰器,能让我们的程序如虎添翼. 装饰器的引入 初期及问题的诞生 假如现在在一个公司,有A B C三个业务部门,还有S一 ...

  8. 介绍python修饰器的书_python修饰器

    1.参数args与kwargs: *args是元组,如def fun(args): pass 传过去的参数是元组形式fun(1,2,3),args=(1,2,3); *kwargs是字典型,如def ...

  9. python修饰器classmate_python3大器----装饰器,迭代器,生成器

    目录 一:闭包: 1:闭包的作用和定义: 2:闭包的形成条件: 3:闭包的经典案例: 4:闭包的原理: 5: 闭包中使用外部函数变量: 二:装饰器: 1:装饰器的定义和作用: 2:装饰器经典案例分析: ...

最新文章

  1. C#代码实现对Windows凭据的管理
  2. 矩阵专职_新的篇章开始了-我将以专职技术作家的身份加入RunCloud
  3. 记录opencv编译过程
  4. mysql主从复制篇-主库有数据
  5. RetinaFace Mxnet转TensorRT
  6. (8)hibernate四种继承映射
  7. ux和ui_设计社交餐厅策展应用程序— UX / UI案例研究
  8. .NET Conf 2021 回顾
  9. excel操作练习_你见过最好的Excel教程有哪些?
  10. matplotlib 中文_Python 关于matplotlib无法显示中文字体的解决方法
  11. 射频信号发生器的应用选择
  12. 骑士问题-BFS求解
  13. Resolution-robust Large Mask Inpainting with Fourier Convolutions 解读
  14. 《无声告白》这不是我想要的生活
  15. 聚观早报|苹果默认不再接受隔空投送;Mete被裁员工将获薪水补偿
  16. 可以发布任务悬赏的app
  17. java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@44f16719 is still active.
  18. 教程篇(7.0) 06. FortiGate安全 日志记录和监控 ❀ Fortinet 网络安全专家 NSE 4
  19. Thingsboard 开源 IoT 物联网平台入门
  20. 0-1背包问题及变种

热门文章

  1. java绘制一个饼图_一个简单的绘制饼图的 Java Bean 实例
  2. mysql数据完整性约束包括_MYSQL回顾(完整性约束相关)
  3. html背景图片只显示一张图片,img只显示图片一部分 或 css设置背景图片只显示图片指定区域(示例代码)...
  4. css怎麽将按钮变长,CSS3 按钮边线环绕渐变缩短和伸长
  5. kubesphere_KubeSphere容器混合云一个人也能轻松运维的K8s
  6. OceanBase之oracle租户的使用体验
  7. ipv6远程连接mysql_如何利用IPv6进行远程桌面连接
  8. Springboot+Mysql企业员工绩效工资管理系统
  9. 编程迷宫_跟我学编程第十期——迷宫游戏
  10. php+oracle新增数据类型,Oracle 修改某个字段的数据类型三种方式