Python mini-web框架3:装饰器

简介: Python mini-web框架3:装饰器

一、看一个例子,来引出装饰器



需求:在不改变下面 test() 函数的情况下,执行函数的情况下先进行其他的步骤,看下面的实现

def set_func(func):
    print("----开始装饰----")
    def run_func():
        print("----验证权限1----")
        func()
    return run_func
def test1():
    print("----test----")
test1 = set_func(test1)
test1()

执行结果是:

----开始装饰----
----验证权限1----
----test----


image.png

  • 分析:test1 = set_fun(test1) 改变了 test1() 的指向,指向了闭包内的run_func()函数,在test()执行的时候,执行的是run_func()函数内的代码
  • 优化: 不想写 test1 = set_fun(test1) 这句代码,我们可以在 def test1():上面写 @set_fun,我们在下面具体看使用。


二、装饰器的介绍以及参数



  • 2.1、简单的来说:一个闭包对一个函数进行装饰就组成了装饰器,如下的例子,@set_fun是一种 语法糖


def set_func(func):
     print("----开始装饰----")
     def run_func():
         print("----验证权限1----")
         func()
     return run_func
@set_func    # @set_fun 与 test1 = set_func(test1) 等价
def test1():
    print("----test----")
test1()

提示:  @set_fun 与 test1 = set_fun(test1)  等价


  • 2.2、装饰器对有 单个参数 函数的装饰(说白了就是传参)


def set_func(func):
     print("----开始装饰----")
     def run_func(num):
          print("----验证权限1----")
          func(num)
     return run_func
@set_func
def test1(num):
     print("----test----%d"%num)
test1(3)

提示:test1指向的是闭包内的run_func函数,传的参数也是给run_func,函数内再调用test1函数,不要绕,好好理解下


  • 2.3、不定长参数的函数装饰(说白了就是参数不定),如下例子


def set_func(func):
    print("----开始装饰----")
    def run_func(*args,**kwargs):
        print("----验证权限1----")
        func(*args,**kwargs)
    return run_func
@set_func
def test1(num,*args,**kwargs):
    print("----test----%d"%num,args,kwargs)
test1(3,2,1,a="1")
  • 打印结果是:


----开始装饰----
----验证权限1----
----test----3 (2, 1) {'a': '1'}


注意:

  • 闭包 里面的 func(*args,**kwargs) 中的 *args**kwargs是解包的意思,传参不能直接传元组与字典,要解包
  • 不可以传 func(args,kwargs),必挂,这样是传了两个参数,一个元组,一个字典,是不对的


  • 2.4、对应有返回值函数进行装饰、通用装饰器


def set_func(func):
      print("----开始装饰----")
      def run_func(*args,**kwargs):
            print("----验证权限1----")
            return func(*args,**kwargs) # 拆包
      return run_func
@set_func
def test1(num,*args,**kwargs):
      print("----test----%d"%num,args,kwargs)
      return "OK"
@set_func
def test2():
      return "OK2"
test1(3,2,1,a="1")
print(test2())
  • 打印结果是:


----开始装饰----
----开始装饰----
----验证权限1----
----test----3 (2, 1) {'a': '1'}
----验证权限1----
OK2


image.png

image.png


  • 2.5、多个装饰器对同一个函数进行装饰


def set_func1(func):
     print("----开始装饰1----")
     def run_func1(*args,**kwargs):
         print("----验证权限1----")
         func(*args,**kwargs) # 拆包
     return run_func1
def set_func2(func):
     print("----开始装饰2----")
     def run_func2(*args,**kwargs):
         print("----验证权限2----")
         func(*args,**kwargs) # 拆包
     return run_func2
@set_func1
@set_func2
def test1(num,*args,**kwargs):
      print("----test----%d"%num,args,kwargs)
test1(3,2,1,a="1")
  • 打印结果:


----开始装饰2----
----开始装饰1----
----验证权限1----
----验证权限2----
----test----3 (2, 1) {'a': '1'}

提示:当多个装饰器装饰同一个函数的时候,装饰从下往上装饰,也就是上面例子中先装饰  set_func2,再装饰set_func1

装饰器在调用之前就已经装好了,组成一个大的闭包空间;执行的时候,先执行后装饰的装饰器里面的代码,后执行前一个被装饰的代码,依次类推,最后执行第一个装饰的闭包内的代码。


  • 2.6、对于同一个装饰器,对多个函数进行装饰
    分析:对于同一个装饰器,对多个函数进行装饰的时候,在没调用之前就会进行装饰,每装饰一个就生成一个闭包。闭包内外部函数的变量指向原函数


def set_func(func):
      print("----开始装饰----")
      def run_func(*args,**kwargs):
             print("----验证权限----")
             func(*args,**kwargs) # 拆包
      return run_func
@set_func
def test1(num,*args,**kwargs):
      print("----test1----%d"%num,args,kwargs)
@set_func
def test2(num,*args,**kwargs):
      print("----test2----%d"%num,args,kwargs)
test1(3,2,1,a="1")
test2(4,5,6,a="2")
  • 打印结果:


----开始装饰----
----开始装饰----
----验证权限----
----test1----3 (2, 1) {'a': '1'}
----验证权限----
----test2----4 (5, 6) {'a': '2'}
  • 2.7、用类对函数进行装饰


class Test(object):
    """docstring for ClassName"""
    def __init__(self, func):
        self.func = func
    def __call__(self):
        print("这里是装饰器添加的功能")
        return self.func()
@Test  # 相当于 get_str = Test(get_str)
def get_str():
     return "测试"
print(get_str())
  • 打印结果:


这里是装饰器添加的功能
测试


三、带有参数的装饰器,是装饰器加参数,如下


def set_level(level):
    def set_func(func):
        def call_func(*args,**kwargs):
           if level ==1 :
                print("权限验证-- %d"%level)
           elif level ==2 :
                print("权限验证-- %d"%level)
           else:
                print("权限验证-- %d"%level)
           func(*args,**kwargs)
        return call_func
    return set_func
@set_level(9)
def test1():
    print("------test1------")
test1()


  • 分析:上面就是给装饰器加参数set_level(9):
  • 1、调用set_level并且将9当做实参传递
  • 2、用上一步调用的返回值当做装饰器对test1函数进行装饰


总结:不要觉得装饰器很难,其实它就是:函数的指向的改变,以闭包为例,闭包作为另一个函数的装饰器,装饰后,在闭包的内部函数再去调用函数,其实就是在函数执行之前先调用闭包内的代码。

目录
相关文章
|
2天前
|
数据采集 存储 中间件
Python进行网络爬虫:Scrapy框架的实践
【8月更文挑战第17天】网络爬虫是自动化程序,用于从互联网收集信息。Python凭借其丰富的库和框架成为构建爬虫的首选语言。Scrapy作为一款流行的开源框架,简化了爬虫开发过程。本文介绍如何使用Python和Scrapy构建简单爬虫:首先安装Scrapy,接着创建新项目并定义爬虫,指定起始URL和解析逻辑。运行爬虫可将数据保存为JSON文件或存储到数据库。此外,Scrapy支持高级功能如中间件定制、分布式爬取、动态页面渲染等。在实践中需遵循最佳规范,如尊重robots.txt协议、合理设置爬取速度等。通过本文,读者将掌握Scrapy基础并了解如何高效地进行网络数据采集。
24 6
Python 装饰器“高级”使用
本文聚焦两个有意思的点 1. 无参和有参装饰器。 @deco vs @deco(arg1,arg2)。 2. 多层装饰器场景。
|
4天前
|
机器学习/深度学习 JSON API
【Python奇迹】FastAPI框架大显神通:一键部署机器学习模型,让数据预测飞跃至Web舞台,震撼开启智能服务新纪元!
【8月更文挑战第16天】在数据驱动的时代,高效部署机器学习模型至关重要。FastAPI凭借其高性能与灵活性,成为搭建模型API的理想选择。本文详述了从环境准备、模型训练到使用FastAPI部署的全过程。首先,确保安装了Python及相关库(fastapi、uvicorn、scikit-learn)。接着,以线性回归为例,构建了一个预测房价的模型。通过定义FastAPI端点,实现了基于房屋大小预测价格的功能,并介绍了如何运行服务器及测试API。最终,用户可通过HTTP请求获取预测结果,极大地提升了模型的实用性和集成性。
14 1
|
5天前
|
开发框架 JSON .NET
ASP.NET Core 标识(Identity)框架系列(三):在 ASP.NET Core Web API 项目中使用标识(Identity)框架进行身份验证
ASP.NET Core 标识(Identity)框架系列(三):在 ASP.NET Core Web API 项目中使用标识(Identity)框架进行身份验证
|
7天前
|
PHP 数据库 开发者
探索PHP的现代演变:从Web开发到框架创新
【8月更文挑战第13天】本文将深入探讨PHP语言自诞生以来的发展历程,特别是它在Web开发领域的演进和在现代框架中的创新。我们将回顾PHP的历史,分析其在不同阶段面临的挑战及解决方案,并讨论PHP如何适应新的编程范式和技术需求,以及这些变化对开发者社区的影响。
18 2
|
7天前
|
安全 前端开发 Java
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443和http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
|
4天前
|
SQL 前端开发 关系型数据库
Python之Web框架Django
Python之Web框架Django
8 0
|
5天前
|
设计模式 API Python
Python Web:Django、Flask和FastAPI框架对比
Python Web:Django、Flask和FastAPI框架对比
13 0
|
6天前
|
缓存 安全 JavaScript
探索PHP的现代演变:从Web开发到框架创新
【8月更文挑战第14天】随着互联网技术的不断进步,PHP语言也在不断地发展和演变。本文将深入探讨PHP在现代Web开发中的地位,分析其语法和功能的演进,并着重讨论PHP框架如何推动Web开发的现代化。同时,文章也将预测PHP在未来技术生态中的可能发展方向。