装饰器预备知识点

1 函数赋值给一个变量

函数名可以像普通变量一样赋值给另一个变量。

def test():
    print("i am just a test function")

ally_test = test   # ally_test也指向这个test函数的地址

test()        # trst+()调用函数
ally_test()   # ally_test()也是调用函数

#output:
i am just a test function
i am just a test function

注意:

  • 函数名不加括号,并没有调用函数
2 嵌套函数

在一个函数内部定义另一个函数,即嵌套函数。

def test():
    def inner1():
        print("i am inner1")
    def inner2():
        print("i am inner2")
    inner1()
    inner2()

test()
#output:
i am inner1
i am inner2

注意:

  • 外层函数调用时,嵌套定义的内层函数也同时被调用。
  • 内层函数在外层函数外不能被访问调用。
3 从函数内返回函数(闭包)

其实,在函数内定义函数的真实目不是去直接调用它,而是以return 的方式返回到函数外。

def test():
    def inner():
        print("i am a inner function")
    return inner  # 返回的是inner,而不是inner()

a = test()
a()  # 调用a,即调用内层函数inner

注意:

  • test函数返回的是inner,而不是inner()。因为加括号inner就会执行,不加括号返回到函数外,即赋值给别的变量而不去执行它。

再看一个:

def outer():
    name = 'alex'
    def inner():
        print("在inner里打印外层函数的变量",name)
    return inner # 注意这里只是返回inner的内存地址,并未执行
f = outer() # .inner at 0x1027621e0>
f()  # 相当于执行的是inner()

关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。也就是说,内部函数会在外部函数返回后被执行。而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。

注意此时outer已经执行完毕,正常情况下outer里的内存都已经释放了,但此时由于闭包的存在,我们却还可以调用inner, 并且inner内部还调用了上一层outer里的name变量。这种粘粘糊糊的现象就是闭包。

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

4 函数作为参数传给另一个函数
def test():
    print("i am coming")

def boss(func):   # func是形参
    print("i want to call a function")
    func()
boss(test)   # test 是实参

#output:
i want to call a function
i am coming

装饰器入门

1 简单装饰器

需求:不改变test函数源码及调用方式的前提下,为test函数增加新功能

def deco(func):
    def inner():
        print("before test function")
        func()
        print("after test function")
    return inner  # 关键点1 

def test():
    print("i am just a test function")

test = deco(test)  # 关键点2
test()  # 关键点3

#output:
before test function
i am just a test function
after test function

deco就是一个装饰器,它是一个普通的函数

它把执行真正业务逻辑的函数test()包裹其中,看起开像test被deco装饰了一样

注意:

  • 关键点1和2:test=deco(test) 先把真正被装饰的函数test传给形参func,再把inner赋值给新变量test。
  • 关键点3:执行test()就是执行inner(),inner里面的func(),就是执行真正被装饰的test函数。
  • 所谓装饰器就是偷梁换柱的障眼法,玩弄内存地址。
2 语法糖
def deco(func):
    def inner():
        print("before test function")
        func()
        print("after test function")
    return inner  # 关键的返回

@deco    # @deco相当于 test=deco(test)
def test():
    print("i am just a test function")

test()

所谓语法糖,就是在被装饰的函数定义上面加上 @deco。这样就不需要写 test = deco(test),直接test()即可。

这样一来就简化了装饰器的使用,只需在定义的位置加上装饰器,调用还和以前一样这样提高了程序的重用性,增加了程序的可读性。

装饰器在Py中试用如此方便都要归因于Py的函数能够像普通对象一样能作为参数传递给其他函数,可以被赋值给其他变量,作为返回值,可以定义在另一个函数内。

3 对有参函数作装饰
def deco(func):
    def inner():
        print("before test function")
        func()
        print("after test function")
    return inner 

@deco
def test():
    print("i am just a test function")
test()

我们知道,执行test()就是执行inner(),name当test需要传参的时候,inner也必须具有传参的功能,即定义装饰器函数的时候,定义inner()的参数。

def deco(func):
    def inner(a,b):
        print("before test function")
        func(a, b)            # 此为执行test(3,4)
        print("after test function")
    return inner 

@deco
def test(a,b):
    print(a+b)
test(3, 4)

#output:
before test function
7
after test function

注意:

  • 如果原函数有参数,那么闭包函数inner必须有参数且保持一样,并且将参数传递给原函数

**如果不确定参数个数,那就用 *args,**kwargs**

def deco(func):
    def inner(*args, **kwargs):
        print("before test function")
        func(*args, **kwargs)
        print("after test function")
    return inner 
4 对带返回值的函数作装饰
def deco(func):
    def inner(a, b):
        print("before test function")
        res = func(a, b)
        print("after test function")
        return res
    return inner

@deco
def test(a, b):
    return a+b

a = test(3, 4)
print(a)

#output:
before test function
after test function
7
5 带参数的装饰器

装饰器还有更大的灵活性,可以带参数。

比如在装饰器中指定日志的等级:

def use_logging(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if level == "warn":
                logging.warn("%s is running" % func.__name__)
            elif level == "info":
                logging.info("%s is running" % func.__name__)
            return func(*args)
        return wrapper

    return decorator

@use_logging(level="warn")
def foo(name='foo'):
    print("i am %s" % name)

foo()

上面的 use_logging 是允许带参数的装饰器。

它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。

我们可以将它理解为一个含有参数的闭包。当我们使用@use_logging(level="warn")调用的时候,Python 能够发现这一层的封装,并把参数传递到装饰器的环境中。

6 类装饰器

装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大,高内聚,封装性等优点。

使用类装饰器主要依靠类的__call__方法,当使用@形式将装饰器加到函数上时,就会调用calla方法。

class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        print ('class decorator runing')
        self._func()
        print ('class decorator ending')

@Foo
def bar():
    print ('bar')

bar()

#output:
class decorator runing
bar
class decorator ending
7 装饰器的顺序

一个函数可以同时定义多个装饰器

@a
@b
@c
def f():
    pass

它的执行顺序时从里往外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于

f = a(b(c(f)))
8 @wraps

python3中装饰器的用法总结的更多相关文章

  1. Python中装饰器的用法

    定义: 装饰器本身就是一个函数 为其他函数提供附加功能 不改变源代码 不改变原调用方式 装饰器=高阶函数+嵌套函数 知识点: 函数本身就是一个变量(意味着可以被复制给一个变量:test=test(1) ...

  2. Python3中装饰器的使用

    较为复杂的装饰器使用: user,passwd = 'hjc',111111 def auth(type): print('auth type:',type) def outwrapper(func) ...

  3. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  4. (转)Python3.5——装饰器及应用详解

    原文:https://blog.csdn.net/loveliuzz/article/details/77853346 Python3.5——装饰器及应用详解(下)----https://blog.c ...

  5. python3.7 装饰器

    #!/usr/bin/env python __author__ = "lrtao2010" #python3.7 装饰器 #装饰器 ''' 定义:本质就是一个函数,作用是为其他函 ...

  6. Python核心技术与实战——十四|Python中装饰器的使用

    我在以前的帖子里讲了装饰器的用法,这里我们来具体讲一讲Python中的装饰器,这里,我们从前面讲的函数,闭包为切入点,引出装饰器的概念.表达和基本使用方法.其次,我们结合一些实际工程中的例子,以便能再 ...

  7. 8.Python中装饰器是什么?

    Python中装饰器是什么? A Python decorator is a specific change that we make in Python syntax to alter functi ...

  8. 第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法

    第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法 上节介绍了Python中类的静态方法,本节将结合案例详细说明相关内容. 一.    案例说明 本节定义了类Sta ...

  9. Python函数装饰器高级用法

    在了解了Python函数装饰器基础知识和闭包之后,开始正式学习函数装饰器. 典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过 ...

随机推荐

  1. jenkin 构建失败 才发邮件通知

    使用场景:自动化测试,一般需要配置定时执行(每天执行一次,没周执行一次),如果有失败,则发邮件给相关人员关注.此时需要使用jenkins的邮件发送配置.修改job的configure配置步骤如下: 1 ...

  2. jsp常用代码

    1.头部 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8&q ...

  3. facenet 人脸识别(二)——创建人脸库搭建人脸识别系统

    搭建人脸库 选择的方式是从百度下载明星照片 照片下载,downloadImageByBaidu.py # coding=utf-8 """ 爬取百度图片的高清原图 &qu ...

  4. idea 2019.1.3最新注册码

    CATF44LT7C-eyJsaWNlbnNlSWQiOiJDQVRGNDRMVDdDIiwibGljZW5zZWVOYW1lIjoiVmxhZGlzbGF2IEtvdmFsZW5rbyIsImFzc ...

  5. 03.Linux-CentOS系统user用户改密码问题

    问题:[user@localhost ~]$ passwdChanging password for user user.Changing password for user.(current) UN ...

  6. 246-基于TI DSP TMS320C6678、Altera FPGA的CPCI处理卡

    基于TI DSP TMS320C6678.Altera FPGA的CPCI处理卡 1.板卡概述  本板卡由我公司自主研发,基于CPCI架构,符合CPCI2.0标准,采用两片TI DSP TMS320C ...

  7. C#高级编程42章 MVC

    42.1 ASP.NET MVC 路由机制 网络介绍链接 按照传统,在很多Web框架中(如经典的ASP.JSP.PHP.ASP.NET等之类的框架),URL代表的是磁盘上的物理文件.例如,当看到请求h ...

  8. java基础复习(一)

    一.常用的DOS命令  打开命令提示符窗口的方式: ① win + R --> 输入cmd --> 回车 ② 开始 --> 搜索程序和文件的框中输入  cmd  --> 回车 ...

  9. I/O性能优化

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11525014.html Linux 系统的 I/O 栈图 I/O性能指标 根据指标找工具 根据工具查指 ...

  10. NET Core+win10+Jenkins+Gogs+open ssh持续集成

    背景 阿里云测试环境一台,带宽1M跟不上,Jenkins安装一个插件耗时很长,于是想在本地搭建Jenkins服务,将生成的安装文件同步到目标服务器上. 技术点有: win10:本地环境是win10,测 ...