• 递归和反射


    递归

    递归算法是一种直接或者间接地调用资深算法的过程。再计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。

    特点

    递归算法解决问题的特点:
    递归就是在过程或者函数里调用自身。
    在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
    递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡递归算法设计程序。
    在递归调用的过程当中系统为每一层的返回点、局部变量等开辟了栈来存储。递归次数过多容易造成堆栈溢出等,所以一般不抵偿递归算法设计程序。

    要求

    递归算法所体现的“重复”一般有三个要求:
    一是每次调用在规模上都有所缩小(通常是减半);
    二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
    三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

    简单递归实现

    def calc(n):
        print(n)
        if n/2 > 1:
            res = calc(n/2)
            print('res:',res)
        print("N:",n)
        return n
    calc(10)
    
    # 执行结果
    10
    5.0
    2.5
    1.25
    N: 1.25
    res: 1.25
    N: 2.5
    res: 2.5
    N: 5.0
    res: 5.0
    N: 10

    斐波那契数列

    def func(arg1,arg2,stop):
        if arg1 == 0:
            print(arg1, arg2)
        arg3 = arg1 + arg2
        print(arg3)
        if arg3 < stop:
            func(arg2, arg3,stop)
    func(0,1,30)
    # 执行结果
    0 1
    1
    2
    3
    5
    8
    13
    21
    34

    尾递归优化

    如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数就是尾递归。采用尾递归算法,可以极大地提高运行效率。需要说明的是,只有当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这样的递归调用才是尾递归。
    优于普通递归的方面:
    1.尾递归通过迭代的方式,不存在子问题被多次计算的情况
    2.尾递归的调用发生在方法的末尾,在计算过程中,完全可以把上一次留在堆栈的状态擦掉,保证程序以O(1)的空间复杂度运行。

    反射

    反射四种内置函数

    1、python中的反射功能是由四种内置函数来提供的,hasattr,setattr,getattr,delattr这四个内置函数分别用于对对象内部执行:检查是否含有某成员,设置某成员,获取某成员,删除成员

    class Foo(object):
    
        def __init__(self):
            self.name = 'tom'
    
        def func(self):
            return 'func'
    
    obj = Foo()
    
    # #### 检查是否含有成员 ####
    hasattr(obj, 'name')
    hasattr(obj, 'func')
    
    # #### 获取成员 ####
    getattr(obj, 'name')
    getattr(obj, 'func')
    
    # #### 设置成员 ####
    setattr(obj, 'age', 18)
    setattr(obj, 'show', lambda num: num + 1)
    
    # #### 删除成员 ####
    delattr(obj, 'name')
    delattr(obj, 'func')

    讨论反射

    2、下面通过例子一步步的讨论反射:
    1)、我们模拟web为例

    def index():
        return 'home.index'
    
    def dev():
        return 'home.dev'
    import home
    url = raw_input("url:")
    if url == "home/dev":
        ret = home.dev()
        print ret
    elif url == "home/index":
        ret = home.index()
        print ret
    else:
        print "404"

    这就是说我们输入对应的url,再进行判断找到符合条件的url,返回值
    下面我们采用反射来进行操作

    url = raw_input("url:")
    #url = home/dev
    controller,action = url.split('/')
    import home
    #action = 字符串
    #去某个容器或模块中,找函数,字符串是函数名,如果有,则获取函数
    func = getattr(home,action)
    #在home中找action,如果有则返回函数名
    ret = func()#函数名加括号,表示执行函数,返回结果ret
    print ret

    这样一来在上面的代码中就不需要再进行判断,只需去在home模块中寻找符合的url,这对于大量的url来说,用反射就简单了。
    2)对四种内置函数产生的结果进行比较

    import home
    print dir(home)#结果为['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'dev', 'index']
    print hasattr(home,'dev')#结果为True
    print getattr(home,'dev')#结果<function dev at 0x026072F0>
    
    setattr(home,'show',lambda x : x + 1)
    print dir(home)
    #结果为['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'dev', 'index', '#show']
    #多了show
    delattr(home,'show')
    print dir(home)
    #结果为['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'dev', 'index']
    #将show删除了

    练习反射

    3)在web上进行测试(练习反射)

    #!/usr/bin/env python
    #coding:utf-8
    from wsgiref.simple_server import make_server
    
    def RunServer(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        url = environ['PATH_INFO']
        temp = url.split('/')[1]
        import home
        #去home模块中检查,是否含有指定的函数
        is_exist = hasattr(home, temp)
        #如果存在指定的函数
        if is_exist:
            #获取函数
            func = getattr(home, temp)
            #执行函数并获取返回值
            ret = func()
            #将函数返回值响应给请求者
            return ret
        else:
            return '404 not found'
    
    if __name__ == '__main__':
        httpd = make_server('', 8001, RunServer)
        print "Serving HTTP on port 8001…"
        httpd.serve_forever()

    3、反射操作类和对象中的成员

    class Foo:
        static_name = 'tom'
        def __init__(self):
            self.name = "eric"
    
        def show(self):
            pass
        @staticmethod
        def static_method():
            pass
        @classmethod
        def class_show(cls):
            pass
    #先看类中都有什么方法
    print Foo.__dict__.keys()
    #['__module__', 'static_method', 'show', 'static_name', 'class_show', '__doc__', '__init__']
    print hasattr(Foo,'class_show') #看类中是否有class_show方法
    obj = Foo()
    #看对象中有什么,结果为{'name': 'eric'}
    print obj.__dict__
    print hasattr(obj,'name') #结果为True
    print hasattr(obj,'show') #结果为True

    为什么对象中只有name,而用hasattr(obj,'show')却显示为True,因为对象中存在类对象指针,对象首先在自己的内存中找,如果没有找到再到类中找,所以就会显示找到,返回结果为True

    其他模块反射效果

    4、上面的操作都是在自己模块的内部执行,接下来看在其他模块执行效果

    import home
    cls = getattr(home,'Foo')
    print cls #home.Foo 得到是类
    obj = cls() #cls是类,类加括号就是实例化,也就是创建对象,执行__init__方法
    name = getattr(obj,'name') #在对象中找name
    print name

    一句话总结反射:在容器中找对象的元素

    动态导入模块

    5、动态导入模块

    try:
        controller,action = raw_input("url:").split("/")
        module = __import__(controller)
        func = getattr(module,action)
        ret = func()
        print ret
    except Exception,e:
        print "请正确输入url"

    参考文档

    https://baike.baidu.com/item/%E9%80%92%E5%BD%92%E7%AE%97%E6%B3%95/4323575?fr=aladdin
    http://crazyforever.blog.51cto.com/7362974/1737341/

    选择了奋斗,以后可以随时还有选择安逸的权力。 但选择了安逸,可能以后就不那么轻易还能有选择奋斗的权力。
  • 相关阅读:
    PNG文件格式具体解释
    opencv2对读书笔记——使用均值漂移算法查找物体
    Jackson的Json转换
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 单词接龙
  • 原文地址:https://www.cnblogs.com/wtli/p/7823454.html
Copyright © 2020-2023  润新知