day_4:计时,递归深度,yield,定制类,Method xxx may be 'static'


斐波那契数列的具体实现方式并不难,但是利用python的诸多特性它会有许多便利的实现;便利一方面是对于大规模计算时候的运行时间短,一方面是占用内存少。同时我在实现过程中遇到的一些小问题。


计时

为了计算代码递归运行的时间,所以顺便介绍一下

关于time模块的官方文档

我选择使用time.process_time()方法
该方法能够返回系统和CPU运行当前进程的时间,不过有个问题就是所返回时间的参考点(大概是指类似计时开始的时间)是未知的,因此返回的时间并不能作为一个真正的参考依据,只有两个不同进程的process_time()返回值之间的差值,才是有意义的。

差值是有意义的,那么对于我的使用已经足以了。

import time
t = time.process_time()

递归深度

以下是我自己写的两种方式获得斐波那契数列的某个值,肯定不会是最优的,但已经能够反映迭代与递归之间的区别了。

import time

class Fibo:
    def get_certain_rec(self, n):  # 递归获取斐波那契数列第n+1个值
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            return self.get_certain_rec(n - 1) + self.get_certain_rec(n - 2)

    @staticmethod
    def get_certain(n):  # 迭代方式
        fibo_0 = 0
        fibo_1 = 1
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            for i in range(2, n+1):
                fibo_n = fibo_0 + fibo_1
                fibo_0, fibo_1 = fibo_1, fibo_n
        return fibo_n
t = time.process_time()
f = Fibo()
f.get_certain(1000)
print(t)
>>>0.0625
t = time.process_time()
f = Fibo()
f.get_certain_rec(1000)
print(t)
>>>RecursionError: maximum recursion depth exceeded in comparison

面对大规模问题的时候,递归方法直接被抛出递归深度达到最大,或许能够通过改变默认递归深度解决该问题,但远不如使用迭代方法来处理。
并且,我们要知道,凡是能够写成递归的方法,就一定也有迭代的解决方法。

t = time.process_time()
f = Fibo()
f.get_certain(100)
print(t)
>>>0.046875
t = time.process_time()
f = Fibo()
f.get_certain_rec(100)
print(t)
>>>
# 虽然没出问题。。。。不过跑了很久都还没出结果

规模还没有特别大,递归就已经跑不动了;而迭代法的时间几乎没有变化,可能是常数级的运行时间。

个人认为,用递归的思想思考如何解决问题,用迭代的方法来实际解决问题。

修改递归深度

import sys
sys.setrecursionlimit(1000000000)

yield

廖雪峰的教程是,关于生成器

  1. 直接print一个生成器返回的是 at 0x00000255F11DA200>,它在内存中的位置。

  2. 需要使用next()方法才能够获取生成器的值;

  3. 生成器generator也是一个可迭代对象,可以被for循环调用;

  4. yield只能在函数中使用;

  5. yield是定义生成器的方法之一;定义的函数中若有yield语句,那么它就是一个generator;

  6. 调用yield b会使得函数中断并返回b;循环的话则会在yield处中断并返回一个值,再次执行时从上次调用yield的地方继续进程。


定制类

来看看廖老师对于斐波那契数列的写法
廖雪峰的教程,关于定制类

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1 # 初始化两个计数器a,b

    def __iter__(self):
        return self # 实例本身就是迭代对象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000: # 退出循环的条件
            raise StopIteration()
        return self.a # 返回下一个值
# 使用了诸如__iter__、__next__等实现了类似iterable的方法

这些以双下划线开头和结尾的特殊类方法,是会被python的函数调用的,因此定义这些特殊方法,可以实现我们对于一些方法的定制,比如为print函数输出的内容添加一种固定格式。

他人总结的定制方法


Method xxx may be 'static'

这是用pycharm写代码时候它提示的一个小问题,认为该方法是个静态方法。

当你在类中定义一个与类的属性无关的方法的时候,便可以认为是在定义一个静态方法。

@staticmethod
def```
# 这就定义了一个静态方法

除此之外还有一个类定义@classmethod
其作用在于使得该方法能够直接被方法调用而无需创建一个实例,不过不经常被使用。


最后附上自己写的斐波那契数列的获得方法

class Fibo:
    @staticmethod
    def get_all(n):  # 用于获取斐波那契数列前n+1个值,也可以通过列表获取任意值
        seq = list()
        for i in range(n+1):
            if len(seq) == 0:
                seq.append(0)
            elif len(seq) == 1:
                seq.append(1)
            else:
                seq.append(seq[i-1] + seq[i-2])
        return seq

    def get_certain_rec(self, n):  # 递归获取斐波那契数列第n+1个值
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            return self.get_certain_rec(n - 1) + self.get_certain_rec(n - 2)

    @staticmethod
    def get_certain(n):  # 迭代方式
        fibo_0 = 0
        fibo_1 = 1
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            for i in range(2, n+1):
                fibo_n = fibo_0 + fibo_1
                fibo_0, fibo_1 = fibo_1, fibo_n
        return fibo_n

你可能感兴趣的:(day_4:计时,递归深度,yield,定制类,Method xxx may be 'static')