IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 浅谈装饰器 -> 正文阅读

[Python知识库]浅谈装饰器

一、装饰器简述

? 在不改变原有函数的调用方式的前提下给函数增加新的功能。它经常用于有切面需求的场景,比如:插入日志、性能测试、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。 概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

二、装饰器分类

2.1 无参装饰器

# -*- coding: utf-8 -*-
# @Time     : 2021/11/25 22:01
# @Author   : Aries
# @File     : 无参装饰器.py
# @Describe : 无参装饰器
# @Software : PyCharm

import time

def decorator(func):

    def inner(*args, **kwargs):
        print(f"不定长位置参数:{args}")
        print(f"不定长关键字参数:{kwargs}")
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print(f"函数运行时间:{end - start}s")
        return result
    return inner

'''
被装饰函数在未调用之前,已经被装饰器函数所装饰
'''
@decorator
def test():
    '''
    被修饰的函数不带参数且无返回值
    :return:
    '''
    print("被修饰的函数不带参数且无返回值!!!")

@decorator
def func(a, b, c=10, d=20):
    '''
    被修饰的函数带参数
    :param a: 位置参数
    :param b: 位置参数
    :param c: 关键字参数
    :param d: 关键字参数
    :return:
    '''

    print("被修饰的函数带参数")
    print(f"位置参数:{a}  {b}")
    print(f"关键字参数:{c}  {d}")

@decorator
def bar(a, c=9):

    print("被修饰的函数带参数且有返回值")
    return a + c

if __name__ == '__main__':
    test()
    print("=" * 50)
    func(5, "李白", c=90, d=100)
    print("=" * 50)
    func(5, "李白")
    print("=" * 50)
    print(bar(100))

2.2 有参装饰器

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 10:41
# @Author   : Aries
# @File     : 有参装饰器.py
# @Describe : 
# @Software : PyCharm

def level(num):

    def decorator(func):
        def inner(*args, **kwargs):
            if num == 1:
                print("权限1验证成功...")
                print("获得登录index页面的权限...")
                return func(*args, **kwargs)
            elif num == 2:
                print("权限2验证成功...")
                print("获得登录商品详情页的权限...")
                return func(*args, **kwargs)
            else:
                raise ValueError("请输入正确的权限验证级别参数:1 or 2")
        return inner
    return decorator


@level(2)
def login(username, pwd):
    if username == "admin" and pwd == "123456":
        return "login success"

    return "login failure"

if __name__ == '__main__':

    print(login("admin", "123456"))

2.3 多层装饰器

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 11:05
# @Author   : Aries
# @File     : 多层装饰器.py
# @Describe : 
# @Software : PyCharm

def permissions(func):
    '''权限验证器'''
    print("权限验证装饰器...")
    def inner(*args, **kwargs):
        username, _ = args
        if username == "admin":
            print("权限验证成功...")
            return func(*args, **kwargs)
        else:
            raise ValueError(f"{username}该用户不具备权限")
    return inner

def identity(func):
    '''身份验证器'''
    print("身份验证装饰器...")
    def inner(*args, **kwargs):
        username, pwd = args
        if username in ("admin", "jess", "lucy") and pwd == "123":
            print("identity success...")
            return func(*args, **kwargs)
        raise ValueError("用户名密码错误,身份验证失败...")
    return inner

'''
装饰顺序由里到外,调用顺序是由外及里
'''
@identity
@permissions
def user(username, pwd):
    print(username, pwd)
    return "login success"

if __name__ == '__main__':
    print(user("admin", "123"))
    #print(user("jess", "123"))

2.4 类装饰器

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 11:37
# @Author   : Aries
# @File     : 类装饰器.py
# @Describe : 
# @Software : PyCharm

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("这里是装饰器添加的功能...")
        print(args)
        print(kwargs)
        a, b = args
        if isinstance(a, int) and isinstance(b, int):
            return self.func(*args, **kwargs)
        else:
            raise ValueError("值错误...")

@Decorator
def add(a, b):

    return a + b

if __name__ == '__main__':
    print(add(10, 20))

    #print(add(10, "abcd"))

2.5 被装饰的对象是类

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 11:05
# @Author   : Aries
# @File     : 装饰器装饰类.py
# @Describe : 
# @Software : PyCharm

def decorator(func):
    def inner(*args, **kwargs):
        print("装饰器装饰类...")
        return func(*args, **kwargs)
    return inner


@decorator
class MyClass:
    def __init__(self):
        print("__init__")

    def eat(self, food):
        print(f"睡醒了吃{food}大餐...")


if __name__ == '__main__':
    a = MyClass()
    a.eat("大鱼大肉")

?

三、装饰器应用场景

2.1 插入日志

? 正式项目的日志模块是结合loggin和日志配置文件生成相应日志的。使用装饰器生成日志仅供参考,不推荐使用。

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 15:50
# @Author   : wljess
# @File     : 日志处理.py
# @Describe : 
# @Software : PyCharm

import logging


def logged(func):
    def inner(*args, **kwargs):
        logging.basicConfig(level=logging.DEBUG  # 设置日志输出格式
                            , filename="demo.log"  # log日志输出的文件位置和文件名
                            , filemode="w"  # 文件的写入格式,w为重新写入文件,默认是追加
                            ,format="%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"
                            # 日志输出的格式
                            # -8表示占位符,让输出左对齐,输出长度都为8位
                            , datefmt="%Y-%m-%d %H:%M:%S"  # 时间输出的格式
                            )
        try:
            result = func(*args, **kwargs)
        except Exception as error:
            logging.exception(error)
        else:
            return result
    return inner

@logged
def foo(a, b):

    return a + b

if __name__ == '__main__':
    print(foo(10, "abc"))

2.2 性能测试

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 15:33
# @Author   : wljess
# @File     : 性能测试.py
# @Describe : 
# @Software : PyCharm

import time
import random

def decorator(func):
    def inner(*args, **kwargs):
        print("装饰器性能测试...")
        s_time = time.perf_counter()
        res = func(*args, **kwargs)
        e_time = time.perf_counter()
        print(f"程序运行时间:{e_time - s_time}s")
        return res
    return inner

@decorator
def loop(num):
    s = 0
    for i in range(num):
        random_num = random.randint(0, 10000000)
        #print(f"循环第{i}次得到的随机数:{random_num}")
        s += random_num
    return s

if __name__ == '__main__':
    print(loop(100))
    print("=" * 50)
    print(loop(1000))
    print("=" * 50)
    print(loop(10000))
    print("=" * 50)
    print(loop(100000))
    print("=" * 50)
    print(loop(10000000))
    print("=" * 50)
    print(loop(100000000))

2.3 缓存

? 在web开发中,缓存是常用来提高服务器的响应速度以及减少数据库压力的用力手段。在处理缓存时,有三个重要的步骤生成缓存键存入缓存获取缓存数据。对不同的缓存软件(Redis,Memcached等)操作基本相同,只是在具体的存储获取环节存在差异。

? 缓存操作主要有两种类型。缓存如浏览器缓存,服务器缓存,代理缓存,硬件缓存工作原理的读写缓存。当处理缓存时,我们总是有大量的内存需要花费大量的时间来读写数据库、硬盘。 缓存则能帮我们加快这些任务。

参考文档:https://cloud.tencent.com/developer/article/1665019

2.3.1 双端队列实现 LRU 机制

from collections import deque
from typing import Any


class LRUCache:
    def __init__(self, cache_size: int):
        """
        
        :param cache_size:  LRU 队列的大小,超过当前大小时,最近最不常使用的元素将过期
        """
        self.cache_size = cache_size
        self.queue = deque()
        self.hash_map = dict()

    def is_queue_full(self):
        return len(self.queue) == self.cache_size

    def set(self, key: str, value: Any):
        if key not in self.hash_map:
            if self.is_queue_full():
                pop_key = self.queue.pop()
                self.hash_map.pop(pop_key)
                self.queue.appendleft(key)
                self.hash_map[key] = value
            else:
                self.queue.appendleft(key)
                self.hash_map[key] = value

    def get(self, key: str):
        if key not in self.hash_map:
            return -1
        else:
            self.queue.remove(key)
            self.queue.appendleft(key)
            return self.hash_map[key]

2.3.2 内置缓存模块

? 在软件或系统开发中,缓存总是必不可少,这是一种空间换时间的技术,通过将频繁访问的数据缓存起来,下一次访问时就可以快速获得期望的结果。一个缓存系统,关键核心的指标就是缓存命中率。LRU是一种常用的缓存算法,即最近最少使用,如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小, LRU算法选择将最近最少使用的数据淘汰,保留那些经常被命中的数据。

# -*- coding: utf-8 -*-
# @Time     : 2021/11/28 13:10
# @Author   : wljess
# @File     : 内置缓存模块.py
# @Describe : 
# @Software : PyCharm

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-


import time
from functools import lru_cache


class Model:

    @lru_cache(maxsize=10)
    def calculate(self, number):
        print(f'calculate({number}) is  running,', end=' ')
        print('sleep  3s  ')
        time.sleep(3)

        return number * 3


if __name__ == '__main__':

    model = Model()

    for i in range(5):
        print(model.calculate(i))

    for i in range(5):
        print(model.calculate(i))

2.4 权限校验

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 16:08
# @Author   : wljess
# @File     : 权限验证.py
# @Describe : 
# @Software : PyCharm


user_list = [
  {'name': 'ad1', 'passwd': '123'},
  {'name': 'ad2', 'passwd': '123'},
  {'name': 'ad3', 'passwd': '123'},
  {'name': 'ad4', 'passwd': '123'}
]


def auth(func):
    def wrapper(*args, **kwargs):
        param = args[0]
        if param != "index.html":
            username = input("请输入用户名:")
            pwd = input("请输入用户密码:")

            # 检查输入的用户名和密码是否正确
            for user in user_list:
                if username == user['name'] and pwd == user['passwd']:
                    if param in ("shop.html", "root"):
                        print("登录成功!!!")
                        return func(*args, **kwargs)

                    raise ValueError("传入参数错误...")

            raise ValueError("输入的用户名和密码不存在,请进入注册页面注册用户...")

        return func(*args, **kwargs)

    return wrapper


@auth
def index(url):
    print(f"主页url:{url} 欢迎来到主页...")


@auth
def home(name):
    print("欢迎回家:%s" % name)


@auth
def shop(url):
    print(f'购物页面路由信息:{url},购物车里有奶茶, 妹妹, 娃娃')


if __name__ == '__main__':
    index('index.html')

    home('root')

    shop('shop.html')
    shop('shop1.html')


2.5 框架路由传参

# -*- coding: utf-8 -*-
# @Time     : 2021/11/26 16:09
# @Author   : wljess
# @File     : 框架路由传参.py
# @Describe : 
# @Software : PyCharm

URL_CONF = {}


def route(url):
    def set_func(func):
        URL_CONF[url] = func

        def inner(*args, **kwargs):
            return func(*args, **kwargs)
        return inner

    return set_func


@route('index.py')
def index():
    return "欢迎访问首页页面"


@route("register.py")
def register():
    return "欢迎来到注册页面"


def application(file_name):
    func = URL_CONF[file_name]

    return func


if __name__ == '__main__':
    app1 = application("index.py")
    app2 = application("register.py")
    print(app1())
    print(app2())

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-11-29 16:16:37  更:2021-11-29 16:18:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 2:34:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码