装饰器相关

高阶函数的两种情况:

1、

把一个函数名当成实参传给另外一个函数(在不修改被装饰函数源代码的情况下,为其添加功能)

import time


def bar():
    time.sleep(2)
    print('in the bar')


def test1(fun_name):
    t1 = time.time()
    fun_name()
    print('run time:%s'%(time.time()-t1))


test1(bar)

2、

返回值中包含函数名(不修改调用方式)

import time


def bar():
    time.sleep(2)
    print('in the bar')


def test1(fun_name):
    return  fun_name


bar = test1(bar)

bar()

高阶函数+嵌套函数则得到装饰器

import time


def timer(fun_name):
    def deco():
        start_time = time.time()
        fun_name()
        end_time = time.time()
        print('running time:%s' % (end_time - start_time))

    return deco


def bar():
    time.sleep(2)
    print('in the bar')


bar = timer(bar)
bar()

但我们一般把装饰器在被装饰函数前面定义,并且用如下的写法代替:

import time


def timer(fun_name):
    def deco():
        start_time = time.time()
        fun_name()  # 在这里调用是bar()这个函数
        end_time = time.time()
        print('running time:%s' % (end_time - start_time))

    return deco


@timer  # bar = timer(bar) 这步其实是调用了timer()这个函数,把bar这个函数进行重新定义
def bar():
    time.sleep(2)
    print('in the bar')


bar()  # 在调用bar的时候,其实调用的是deco()这个函数

  

可以理解为,先用第一种高阶函数加上想要的功能,再重新覆盖定义这个函数,再用函数嵌套,就得到了我们想要的装饰器的效果

如果有参数:

import time


def timer(fun_name):
    def deco(*args,**kwargs):
        start_time = time.time()
        fun_name(*args,**kwargs)
        end_time = time.time()
        print('running time:%s' % (end_time - start_time))

    return deco


@timer  # bar = timer(bar)
def bar():
    time.sleep(2)
    print('in the bar')


@timer
def bar2(name,age):
    print(name,age)


bar()
bar2('simon',22)

  

终极版:原函数带有返回值,装饰器本身带参数

__author__ = "Alex Li"
import time

user, passwd = 'alex', 'abc123'


def auth(auth_type):
    print("auth func:", auth_type)

    def outer_wrapper(func):
        def wrapper(*args, **kwargs):
            print("wrapper func args:", *args, **kwargs)
            if auth_type == "local":
                username = input("Username:").strip()
                password = input("Password:").strip()
                if user == username and passwd == password:
                    print("\033[32;1mUser has passed authentication\033[0m")
                    res = func(*args, **kwargs)  # from home
                    print("---after authenticaion ")
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            elif auth_type == "ldap":
                print("搞毛线ldap,不会。。。。")

        return wrapper

    return outer_wrapper


def index():
    print("welcome to index page")


@auth(auth_type="local")  # home = wrapper()
def home():
    print("welcome to home  page")
    return "from home"


@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs  page")


index()
print(home())  # wrapper()
bbs()

 

几个装饰器的小练习和写的答案

一:编写3个函数,每个函数执行的时间是不一样的,

提示:可以使用time.sleep(2),让程序sleep 2s或更多,

二:编写装饰器,为每个函数加上统计运行时间的功能

提示:在函数开始执行时加上start=time.time()就可纪录当前执行的时间戳,函数执行结束后在time.time() - start就可以拿到执行所用时间

三:编写装饰器,为函数加上认证的功能,即要求认证成功后才能执行函数

四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码

提示:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式

答案:

# -*- coding: utf-8 -*-
import time, os

if not os.path.exists('login_for Decorator.txt'):
    with open('login_for Decorator.txt', 'w', encoding='utf-8')as f:
        f.write(str({'name': 'simon', 'password': '123'}))
with open('login_for Decorator.txt', 'r', encoding='utf-8')as f2:
    dict_list = eval(f2.read())

name, password = dict_list['name'], dict_list['password']

login_status = 0


# 验证是否登录,一次登录,后面不再需要登录则可以运行
def login(func):
    def deco(*args, **kwargs):
        global login_status
        if not login_status:
            if_wrong = 1  # 默认密码是错误的
            while if_wrong:  # 如果输入错误,就一直循环输入
                _name = input('your name :').strip()
                _password = input('type your password:').strip()
                if _name == name and _password == password:
                    print('welcome %s login' % _name)
                    login_status = 1
                    if_wrong = 0
                    func()
                else:
                    pass  # print('不应该出现这个')
        else:
            func()

    return deco


# 此装饰器的作用是打印函数运行时间
def timer(func):
    def deco(*args, **kwargs):
        t1 = time.time()
        func()
        print('running time:%s' % (time.time() - t1))

    return deco


@login
def fun1():
    time.sleep(3)
    print('here is fun1')


@login
def fun2():
    time.sleep(3)
    print('here is fun2')


@login
def fun3():
    time.sleep(3)
    print('here is fun3')


fun1()
fun2()
fun3()

  

posted on 2018-04-08 21:03  simon002  阅读(123)  评论(0编辑  收藏  举报

导航