错位的梦寐

Python 装饰器

2020-05-20


装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。

装饰器

有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

装饰器:本质是函数,功能是为其它函数添加附加功能

==原则:==

  • 不修改被修饰函数的源代码
  • 不修改被修饰函数的调用方式

装饰器=高阶函数+函数嵌套+闭包

import  time

def timer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('函数运行时间%s'%(stop_time-start_time))
        return  res
    return wrapper

@timer     #cal=timer(cal)
def cal(l):
    res=0
    for i in l :
        time.sleep(0.1)
        res+=i
    return  res

res=cal(range(100))
print(res)


输出:
函数运行时间10.065450668334961
4950

高阶函数

高阶函数的定义:

  • 函数接收的参数是一个函数名
  • 函数的返回值是一个函数名
  • 满足上述条件的其中一个,都可以称之为高阶函数

函数嵌套

在一个函数中定另外一个函数

def father(auth_type):
    # print('from father %s' %name)
    def son():
        # name='linhaifeng_1'
        # print('我的爸爸是%s' %name)
        def grandson():
            print('我的爷爷是%s' %auth_type)
        grandson()
    # print(locals())
    #{'son': <function father.<locals>.son at 0x0000022F74C6CCA8>, 'auth_type': 'filedb'}
    #函数即变量 
    #locals()同级的局部变量,name,son
    son()
# father('linhaifeng')
father('filedb')

闭包函数

一 什么是闭包?

#内部函数包含对外部作用域而非全局作用域的引用

#提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来

        def counter():
            n=0
            def incr():
                nonlocal n
                x=n
                n+=1
                return x
            return incr

        c=counter()
        print(c())
        print(c())
        print(c())
        print(c.__closure__[0].cell_contents) #查看闭包的元素

二 闭包的意义与应用

#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,
# 该函数无论在何处调用,优先使用自己外层包裹的作用域

#应用领域:延迟计算(原来我们是传参,现在我们是包起来)
from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()
    return get

baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))
import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
    return wrapper

@timmer #test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
test()
import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
    return wrapper


def test():
    time.sleep(3)
    print('test函数运行完毕')


res=timmer(test)  	#返回的是wrapper的地址
res()  				#执行的是wrapper()

test=timmer(test)  	#返回的是wrapper的地址
test()  			#执行的是wrapper()

#  @timmer  就相当于 test=timmer(test)

@timmer 	#test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
test()

加上返回值的装饰器

import time
def timmer(func): 	#func=test
    def wrapper():
        start_time=time.time()
        res=func() 	#就是在运行test()
        		   	#res为test()的返回值	
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
        return res
    return wrapper

@timmer 	#test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
    return '这是test的返回值'

res=test()  #运行test()相当于在运行wrapper
			#res相当于wrapper的返回值
print(res)

加上参数的装饰器

执行test() 就相当于执行timmer()的返回值——wrapper 修改wrapper()就达到了修改test() 的目的

import time
def timmer(func): #func=test1
    def wrapper(*args,**kwargs): #test('linhaifeng',age=18)  args=('linhaifeng')  kwargs={'age':18}
        start_time=time.time()
        res=func(*args,**kwargs) 
        # 运行func()就是在运行test(),test()有参数,func也应该有相应的参数(个数),
        # 此时func的参数值来自wrapper
        # func(*('linhaifeng'),**{'age':18})
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
        return res
    return wrapper

@timmer #test=timmer(test)
def test(name,age):
    time.sleep(3)
    print('test函数运行完毕,名字是【%s】 年龄是【%s】' %(name,age))
    return '这是test的返回值'

@timmer
def test1(name,age,gender):
    time.sleep(1)
    print('test1函数运行完毕,名字是【%s】 年龄是【%s】 性别【%s】' %(name,age,gender))
    return '这是test的返回值'
# 执行test()就是在运行wrapper
#test()传入两个参数, 需要修改wrapper,传入相应的参数
res=test('linhaifeng',age=18) 
print(res)
test1('alex',18,'male')
def test2(name,age,gender): 
    print(name)
    print(age)
    print(gender)
    '''
    alex
    18
    male
    '''

def test1(*args,**kwargs):
    print(args,kwargs)      #('alex', 18, 'male') {}
    # print(*args, **kwargs)  # alex 18 male
    test2(*args,**kwargs)   #args=('alex',18,'male','x','y') kwargs={}
test1('alex',18,'male')
def test2(name,age,gender): #test2(*('alex',18,'male','x','y'),**{})
    #name,age,gender=('alex',18,'male','x','y')
    print(name)
    print(age)
    print(gender)
    '''
    alex
    18
    male
    '''

def test1(*args,**kwargs):
    print(args,kwargs)      #('alex', 18) {'gender': 'male'}
    # print(*args, **kwargs)  # {}
    test2(*args,**kwargs)   #args=('alex',18,'male','x','y') kwargs={}

test1('alex',18,gender='male')

带验证功能装饰器

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]
current_dic={'username':None,'login':False}


def auth_func(func):
    def wrapper(*args,**kwargs):
        if current_dic['username'] and current_dic['login']:
            res = func(*args, **kwargs)
            #如果fun 没有返回值 res为None
            return res
        username=input('用户名:').strip()
        passwd=input('密码:').strip()
        for user_dic in user_list:
            if username == user_dic['name'] and passwd == user_dic['passwd']:
                current_dic['username']=username
                current_dic['login']=True
                res = func(*args, **kwargs)
                return res
        else:
            print('用户名或者密码错误')

    return wrapper

@auth_func
def index():
    print('欢迎来到京东主页')

@auth_func
def home(name):
    print('欢迎回家%s' %name)

@auth_func
def shopping_car(name):
    print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

print('before-->',current_dic)
index()
print('after--->',current_dic)
home('产品经理')
# shopping_car('产品经理')

带参数验证功能装饰器


user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]
current_dic={'username':None,'login':False}

def auth(auth_type='filedb'):
    def auth_func(func):
        def wrapper(*args,**kwargs):
            print('认证类型是',auth_type)
            if auth_type == 'filedb':
                if current_dic['username'] and current_dic['login']:
                    res = func(*args, **kwargs)
                    return res
                username=input('用户名:').strip()
                passwd=input('密码:').strip()
                for user_dic in user_list:
                    if username == user_dic['name'] and passwd == user_dic['passwd']:
                        current_dic['username']=username
                        current_dic['login']=True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print('用户名或者密码错误')
            elif auth_type == 'ldap':
                print('鬼才特么会玩')
                res = func(*args, **kwargs)
                return res
            else:
                print('鬼才知道你用的什么认证方式')
                res = func(*args, **kwargs)
                return res

        return wrapper
    return auth_func

@auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type  --->index=auth_func(index)
def index():
    print('欢迎来到京东主页')

@auth(auth_type='ldap')
def home(name):
    print('欢迎回家%s' %name)
#
@auth(auth_type='sssssss')
def shopping_car(name):
    print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

# print('before-->',current_dic)
# index()
# print('after--->',current_dic)
# home('产品经理')
shopping_car('产品经理')

参考: 点击获取 参考:https://foofish.net/python-decorator.html


Comments

Content