Seven-递归函数和装饰器函数

递归函数

递归的定义——在一个函数里再调用这个函数本身

递归的最大深度——997

递归函数如果不受外力的阻止就会一直执行下去,但每一次函数调用都会产生一个属于它自己的名称空间,如果一直调用下去,就会造成名称空间占用太多内存的问题,于是python为了杜绝此类现象,强制的将递归层数控制在了997

def foo(n):
    print(n)
    n += 1
    foo(n)
foo(1)
测试最大递归深度

Of course,997是python为了我们程序的内存优化所设定的一个默认值,我们还是可以通过一些方式修改默认值的

import sys
print(sys.setrecursionlimit(100000))
修改递归最大深度

不过不推荐修改默认递归深度,因为如果用997层递归都没有解决的问题不是代码太烂那就是不适合使用递归来解决

递归示例

我们想知道alex多大了?现只知道alex比 egon 大两岁。

你想知道alex多大,你是不是还得去问egon?egon说,我不告诉你,但我比武sir大两岁。

你又问武sir,武sir也不告诉你,他说他比金鑫大两岁。

那你问金鑫,金鑫告诉你,他40了。。。

这个时候你是不是就知道了?alex多大?

def age(n):
    if n == 4:
        return 40
    return age(n+1)+2
print(age(1))

# 46

二分查找算法

定义:二分查找又称折半查找

优点:比较次数少,查找速度快,平均性能好

缺点:要求待查表为有序表,且执行插入删除操作困难

因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设列表中元素是按升序排列,将列表中间位置记录的值与所需查找的值比较,如果两者相等,则查找成功;否则利用中间位置记录将列表分成前、后两个子表,如果中间位置记录的值大于需要查找的值,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,查找成功,或直到子表不存在为止,此时查找不成功

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

def func(l,aim):
    mid = (len(l)-1)//2
    if l:
        if aim > l[mid]:
            func(l[mid+1:],aim)
        elif aim < l[mid]:
            func(l[:mid],aim)
        elif aim == l[mid]:
            print("bingo",mid)
    else:
        print('找不到')
func(l,66)
func(l,6)
简单版
def find_2(l,aim,start=0,end=None):
    if end == None:end = len(l) - 1
    if start <= end:
        mid = (end-start) // 2  + start
        if l[mid] > aim:
            find_2(l,aim,start,mid-1)
        elif l[mid] < aim:
            find_2(l,aim,mid+1,end)
        else:
            print(aim,mid)
    else:
        print('找不到这个值')
l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]
find_2(l,32)

# 32 10
升级版

阶乘

def f(n):
    if n==1:
        return 1
    return n*f(n-1)
print(f(3))

# 6

斐波那契数列

def fib(n):
    if n==1 or n==2:
        return 1
    return fib(n-1)+fib(n-2)
print(fib(8))

# 21

三级菜单

menu = {
    '北京': {
        '海淀': {
            '五道口': {
                'soho': {},
                '网易': {},
                'google': {}
            },
            '中关村': {
                '爱奇艺': {},
                '汽车之家': {},
                'youku': {},
            },
            '上地': {
                '百度': {},
            },
        },
        '昌平': {
            '沙河': {
                '老男孩': {},
                '北航': {},
            },
            '天通苑': {},
            '回龙观': {},
        },
        '朝阳': {},
        '东城': {},
    },
    '上海': {
        '闵行': {
            "人民广场": {
                '炸鸡店': {}
            }
        },
        '闸北': {
            '火车战': {
                '携程': {}
            }
        },
        '浦东': {},
    },
    '山东': {},
}

def menu_3(menu):
    while True:
        for key in menu:
            print(key)
        choice=input('选择:')
        if choice == 'q' or choice == 'b':
            return choice
        elif choice in menu and menu_3(menu[choice]):
            borq = menu_3(menu[choice])
            if borq == 'q':
                return 'q'
menu_3(menu)

装饰器函数

装饰器的本质——一个闭包函数

装饰器的功能——在不修改原函数本身及其调用方式的前提下在原函数前后添加功能

def timer(func):
    def inner(*args,**kwargs):
        '''执行函数之前要做的'''
        re = func(*args,**kwargs)
        '''执行函数之后要做的'''
        return re
    return inner
装饰器的固定格式
from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper
装饰器的固定格式—wraps

开放封闭原则

  对扩展是开放的

  任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何关心和修改,所以必须允许代码扩展、添加新功能

  对修改是封闭的

  我们所写的程序都是要交给用户使用的,如果我们随意对其进行修改,很有可能影响已经在使用程序的用户

装饰器完美的遵循了这个开放封闭原则

装饰器的形成过程

import time

def func1():
    print('in func1')

def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

func1 = timer(func1)
func1()
装饰器—简单版

为了省略上面那一次赋值调用,python为我们提供了一句语法糖来解决这个问题

import time
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

@timer   #==> func1 = timer(func1)
def func1():
    print('in func1')


func1()
装饰器—语法糖
def timer(func):
    def inner(a):
        start = time.time()
        func(a)
        print(time.time() - start)
    return inner

@timer
def func1(a):
    print(a)

func1(1)
带参数的装饰器
带参数的装饰器—other
import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func1 = timer(func1)
def func1(a,b):
    print('in func1')

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
可以hold住所有函数传参
import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func2('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
带返回值的装饰器

正常情况下一些查看函数信息的方法都会在装饰器这里失效

def index():
    '''这是一个主页信息'''
    print('from index')

print(index.__doc__)    #查看函数注释的方法
print(index.__name__)   #查看函数名的方法
查看函数信息

为了不让它们失效,需要在装饰器上加上一点来完善

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)
print(index.__name__)
装饰器—wraps

多个装饰器装饰同一个函数

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()
多个装饰器装饰同一个函数

 

 

 

 

 

 

转载于:https://www.cnblogs.com/gumo/p/7827126.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值