python中函数装饰器

函数装饰器

 

 

# 装饰器的概念

 

- 装饰器的实现是函数里面嵌套函数;

- 装饰器的本质是一个函数, 它可以让其他函数在不需要做任何代码改动的前提下增加额外的功能;

- 装饰器需要传递一个函数, 返回值也是一个函数对象.

 

 

# 装饰器的应用场景

- 计时器

- 记录日志

- 用户登录验证

- 函数参数验证

# ATM

 

# 用户使用ATM的时候, 执行程序之前祝福语==“国庆节快乐”,

#                   执行程序之后打个广告===="欢迎再次光临西部开源.....".

 

 

 

# 1. 解决问题: 在函数执行之前和执行之后添加功能, 调用函数的方式改变了.

# 2. 不改变原有函数的调用方法: 函数里面潜逃函数, 并且返回嵌套的函数login = desc(login)

 

def desc(fun):  # fun = login   #1).  需要传递一个函数, 要装饰的函数

    def add_info():             # 2). 装饰器函数里面嵌套函数

        print("五一快乐")

        fun()  # login()

        print("欢迎再次光临西部开源.....")

    return add_info             #3). 返回值是嵌套的函数对象

 

# 语法糖

@desc   # login = desc(login)    # 4). 如何调用装饰器(两种方式)

def login():

    # print("国庆节快乐")

    print("login......")

    # print("欢迎再次光临西部开源.....")

# login = desc(login)  # 返回值是一个函数

# login()

 

login()

 

 

def logout():

    print("logout......")

 

logout = desc(logout)

logout()

 

def saveMoney():

    print("存钱........")

 

 

 

def transferMoney():

    print("转账.........")

 

 

 

 

计时器的实现

# 装饰器需求: 获取每个函数的执行时间

#       1).函数执行之前计算时间;

#       2).函数执行之后计算时间

 

 

#  实验1:看字符串拼接的效率

#           1). “hello” + "world"

#           2). " ".join(['hello', “world”])

 

 

# 实验2: 检测列表生成式和map的效率高低, n为函数传入的参数===两者实力相当

#       1). [n*2 for i in range(n)]

#       2). map(lambda x:x*2, range(n))

 

 

 

import random

import string

import time

li = [ random.choice(string.ascii_letters) for i in range(100)]

 

def timeit(fun): # fun_list

    def wrapper(*args, **kwargs):   # 接收可变参数和关键字参数

        # args: 元组   kwargs: 字典  args=(5,)

        # 函数执行之前

        start_time = time.time()

        # 执行函数

        fun(*args, **kwargs)  # args解包, 5,|  对于元组解包, 对于字典解包

        # 执行函数之后

        end_time = time.time()

        print("运行时间为:%.6f" % (end_time - start_time))

    return  wrapper

 

 

@timeit

def con_add():

    s = ''

    for i in li:

        s += (i+",")

    print(s)

 

 

@timeit

def join_add():

    print(",".join(li))

 

 

@timeit   #  fun_list=timeit(fun_list)   # fun_list = wrapper

def fun_list(n):

    print([2*i for i in range(n)])

 

@timeit

def fun_map(n):

    print(list(map(lambda x:x*2, range(n))))

 

con_add()

join_add()

fun_list(500000)   #

fun_map(500000)

 

 

 

 

如何保留被装饰函数的函数名和帮助文档

import random

import string

import time

import functools

# 高阶函数的一些方法

from functools import reduce

 

# 问题1: 装饰的函数有返回值的解决方法:

# 问题2:如何保留被装饰函数的函数名和帮助文档信息. @functools.wraps(fun)

def timeit(fun): # fun_list

    """这是一个装饰器timeit"""

    @functools.wraps(fun)

    # 可以保留被装饰函数的函数名和帮助文档信息.

    def wrapper(*args, **kwargs):   # 接收可变参数和关键字参数  # 100

        """这是一个wrpper函数"""

        # args: 元组   kwargs: 字典  args=(100,)

        # 函数执行之前

        start_time = time.time()

        # 执行函数

        res = fun(*args, **kwargs)  # args解包, 100,|  对于元组解包, 对于字典解包

        # fun_list(100)

        # 执行函数之后

        end_time = time.time()

        print("运行时间为:%.6f" % (end_time - start_time))

        return res

    return  wrapper

 

@timeit         # fun_list=timeit(fun_list)  # fun_list = wrapper

def fun_list(n):

    """这是fun_list函数, 被timeit装饰"""

    return [2*i for i in range(n)]

 

@timeit

def fun_map(n):

    """这是fun_map函数"""

    return   map(lambda x:x*2, range(n))

 

@timeit

def fun():

    print("hello")

 

# print(fun_list(100))   # wrapper(100)

# print(fun_map(100))

# fun()

 

 

print(fun_list.__name__)

print(fun_list.__doc__)

 

 

 

 

 

 

装饰器实现添加日志

# 创建装饰器, 要求如下:

# 1. 创建add_log装饰器, 被装饰的函数打印日志信息;

# 2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx

 

 

import functools

import time

 

# format

def add_log(fun):

    @functools.wraps(fun)

    def wrapper(*args, **kwargs):

        # run_time = time.ctime()

        # fun_name = fun.__name__

        start_time = time.time()

        res = fun(*args, **kwargs)

        end_time = time.time()

        print("[%s] 函数名: %s, 运行时间:%.5f, 运行返回值结果:%d"

              %(time.ctime(), fun.__name__, end_time-start_time, res )

              )

        return res

    return wrapper

 

@add_log

def add(x,y):

    time.sleep(0.1)

    return x+y

 

print(add(1,2))

 

 

 

 

 

带有多个装饰器的函数

 @is_login, @is_admin

 

 

 

 需求: 用户登陆验证的装饰器is_login

       1). 如果用户登陆成功, 则执行被装饰的函数;

       2). 如果用户登陆不成功, 则执行登陆函数

 

 

 需求: 判断登陆用户是否未管理员is_admin(此处管理员只有一个为:admin用户)

      1).如果用户为管理员, 则执行被装饰的函数;

      2).如果用户不是管理员, 则报错;

 import functools

 login_users = ['admin', 'root']

 

 

 

 def is_admin(fun):

     @functools.wraps(fun)

     def wrapper(*args, **kwargs):

 

         if kwargs.get("name") == 'admin':

             res = fun(*args, **kwargs)

             return  res

         else:

             return "Error: 您没有权限访问该网站"

     return wrapper

 

 def is_login(fun):  # fun: writeBlog

     @functools.wraps(fun)

     def wrapper(*args, **kwargs):   # name="admin"  # kwargs={"name":"admin"}

         # 判断写博客的这个用户是否登陆成功;

         if kwargs.get("name") in login_users:

             res = fun(*args, **kwargs)

             return res

         else:

             res=login()

         return res

     return wrapper

 

 必须登陆成功

 @is_login    # writeBlog = is_login(writeBlog)

 @is_admin     # 先判断是否为admin用户

 def writeBlog(name):

     return "编写博客"

 

 def login():

     return "登陆。。。。"

 

 是否登陆成功都可以执行代码

 def news():

     print("新闻......")

 

 print(writeBlog(name="root"))

 

 

 

 

def makebold(fun):

    print("bold1")

    def wrapper1(*args, **kwargs):

        print("bold2")

        return  fun(*args, **kwargs)  # wrapper

    return  wrapper1

 

def makei(fun):   # fun=login

    print("i1")

    def wrapper(*args, **kwargs):

        print("i2")

        return  fun(*args, **kwargs)

    return  wrapper

 

  当有多个装饰器时, 从下到上调用装饰器,

  真实wrapper内容执行是从上到下执行.

@makebold  # login = makebold(login)   # login为wrapper1

@makei    # login = makei(login)    # login为wrapper

def login():

    return "登陆"

print(login())

 

 

 

 

带有参数的装饰器

 创建装饰器, 要求如下:

 1. 创建add_log装饰器, 被装饰的函数打印日志信息;

 2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx

 

 

import functools

import time

 

 format

def log(kind):  # kind="debug"

    def add_log(fun):

        @functools.wraps(fun)

        def wrapper(*args, **kwargs):

            # run_time = time.ctime()

            # fun_name = fun.__name__

            start_time = time.time()

            res = fun(*args, **kwargs)

            end_time = time.time()

            print("<%s> [%s] 函数名: %s, 运行时间:%.5f, 运行返回值结果:%d"

                  %(kind, time.ctime(), fun.__name__, end_time-start_time, res )

                  )

            return res

        return wrapper

    return  add_log

@log("debug")

  log("debug")==> 返回值是add_log

  add=add_log(add)

def add(x,y):

    time.sleep(0.1)

    return x+y

print(add(1,2))

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值