Python装饰器代码详解

目录
  • 一、理解装饰器
  • 二、装饰器原型
    • 1、不带参数的装饰器
    • 2.带参数的被装饰的函数
    • 3.带参数的装饰器
    • 4.使用类作为装饰器
    • 5.使用对象作为装饰器
    • 6.多层装饰器的嵌套
  • 总结

一、理解装饰器

所有东西都是对象(函数可以当做对象传递)
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

def function_one():
    print("测试函数")
#可以将一个函数赋值给一个变量,比如
foo =function_one #这里没有在使用小括号,因为我们并不是在调用function_one函数,而是在将它放在foo变量里。
foo()
'''
测试函数
Process finished with exit code 0
'''

闭包的概念:

1)函数嵌套

2)内部函数使用外部函数的变量

3)外部函数的返回值为内部函数

示例:

def outer_function(message):
    def inner_function():
        print(message)
    return inner_function
func = outer_function("你好")
func() #你好

二、装饰器原型

装饰器的作用就是 不修改源代码以及原函数调用方式的情况下 给原函数增加新的功能。

#将函数作为参数传给另一个函数
def decorator_function(original_function):
    def wrapper_function():
    	print('wrapper executed this before {}'.format(original_function.__name__))
        original_function()
    return wrapper_function
    '''
    返回wrapper_function而不是wrapper_function();这是因为当你把一对小括号放在后面,这个函数就会执行;
    然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。
	'''
def display():
    print('display function ran')
decorator_display = decorator_function(display)
decorator_display()

运行结果:

wrapper executed this before display
display function ran
Process finished with exit code 0

1、不带参数的装饰器

def decorator_function(original_function):
    def wrapper_function():
        print('wrapper executed this before {}'.format(original_function.__name__))
        original_function()
    return wrapper_function
@decorator_function
def display():  #等价于display =decorator_function(display)
    print('display function ran')
display()

运行结果:

wrapper executed this before display
display function ran

Process finished with exit code 0

2.带参数的被装饰的函数

def decorator_function(original_function):
    def wrapper_function(*args,**kwargs):
        print('wrapper executed this before {}'.format(original_function.__name__))
        original_function(*args,**kwargs)
    return wrapper_function
@decorator_function
def display():
    print('display function ran')
@decorator_function
def display_info(name,age):
    print('display_info ran with arguments ({},{})'.format(name,age))
display()
print('='*50)
display_info('Michal',20)

运行结果:

wrapper executed this before display
display function ran
==================================================
wrapper executed this before display_info
display_info ran with arguments (Michal,20)

Process finished with exit code 0

运行如下代码会出现一个问题

def decorator_function(original_function):
    def wrapper_function(*args,**kwargs):
        print('wrapper executed this before {}'.format(original_function.__name__))
        original_function(*args,**kwargs)
    return wrapper_function
@decorator_function
def display():
    print('display function ran')
@decorator_function
def display_info(name,age):
    print('display_info ran with arguments ({},{})'.format(name,age))
display_info = decorator_function(display_info)
print(display_info.__name__)

wrapper_function

Process finished with exit code 0

输出的应该是display_info,这里的函数被wrapper_function替代了,重写了我们函数的名字和注释文档(docstring)。Python中可以使用functools.wraps来解决这个问题。

from functools import wraps
def decorator_function(original_function):
    @wraps(original_function)
    def wrapper_function(*args,**kwargs):
        print('wrapper executed this before {}'.format(original_function.__name__))
        original_function(*args,**kwargs)
    return wrapper_function
@decorator_function
def display():
    print('display function ran')
@decorator_function
def display_info(name,age):
    print('display_info ran with arguments ({},{})'.format(name,age))
display_info = decorator_function(display_info)
print(display_info.__name__)

运行结果:

display_info

Process finished with exit code 0

3.带参数的装饰器

在函数中嵌入装饰器

from functools import wraps
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator
@logit()
def myfunc1():
    pass
myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
@logit(logfile='func2.log')
def myfunc2():
    pass
myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串

4.使用类作为装饰器

class myDecorator(object):
     def __init__(self, f):
         print("inside myDecorator.__init__()")
         f() # Prove that function definition has completed
     def __call__(self):
         print("inside myDecorator.__call__()")
 ​
 @myDecorator
 def aFunction():
     print("inside aFunction()")
 ​
 print("Finished decorating aFunction()")
 ​
 aFunction()

运行结果:

inside myDecorator.__init__()
inside aFunction()
Finished decorating aFunction()
inside myDecorator.__call__()
Process finished with exit code 0

被装饰后的函数aFunction()实际上已经是类myDecorator的对象。当再调用aFunction()函数时,实际上就是调用类myDecorator的对象,因此会调用到类myDecorator的__call__()方法。

因此使用类作为装饰器装饰函数来对函数添加一些额外的属性或功能时,一般会在类的__init__()方法中记录传入的函数,再在__call__()调用修饰的函数及其它额外处理。

class entryExit(object):
     def __init__(self, f):
         self.f = f
     def __call__(self):
         print("Entering", self.f.__name__)
         self.f()
         print("Exited", self.f.__name__)
 ​
 @entryExit
 def func1():
     print("inside func1()")
 ​
 @entryExit
 def func2():
     print("inside func2()")
 ​
 func1()
 func2()

运行结果:

Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2

Process finished with exit code 0

5.使用对象作为装饰器

空参:

from functools import wraps
class decorator_class:
    def __init__(self):
        print('执行decorator_class类的__init__()方法')
    def __call__(self, original_function):
        print('执行decorator_class类的__call__()方法')
        @wraps(original_function)
        def wrapped_function(*args, **kwargs):
            print('call method executed this before {}'.format(original_function.__name__))
            print('执行' + original_function.__name__ + '()')
            original_function(*args, **kwargs)
            print(original_function.__name__ + '()执行完毕')
        return wrapped_function
@decorator_class()
def display_info(name,age):
    print('display_info ran with arguments ({},{})'.format(name,age))
display_info('Michael',20)

运行结果如下:

执行decorator_class类的__init__()方法
执行decorator_class类的__call__()方法
call method executed this before display_info
执行display_info()
display_info ran with arguments (Michael,20)
display_info()执行完毕

Process finished with exit code 0

带参数:

from functools import wraps
class decorator_class:
    def __init__(self,arg1, arg2):
        print('执行decorator_class类的__init__()方法')
        self.arg1 =arg1
        self.arg2=arg2
    def __call__(self, original_function):
        print('执行decorator_class类的__call__()方法')
        @wraps(original_function)
        def wrapped_function(*args, **kwargs):
        	print('执行wrapped_function()')
            print('call method executed this before {}'.format(original_function.__name__))
            print('装饰器参数:', self.arg1, self.arg2)
            print('执行' + original_function.__name__ + '()')
            original_function(*args, **kwargs)
            print(original_function.__name__ + '()执行完毕')
        return wrapped_function
@decorator_class('Hello', 'World')
def display_info(name,age):
    print('display_info ran with arguments ({},{})'.format(name,age))
display_info('Michael',20)

运行结果如下:

执行decorator_class类的__init__()方法
执行decorator_class类的__call__()方法
执行wrapped_function()
call method executed this before display_info
装饰器参数: Hello World
执行display_info()
display_info ran with arguments (Michael,20)
display_info()执行完毕

Process finished with exit code 0

示例2:

from functools import wraps
class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile
    def __call__(self, func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile并写入
            with open(self.logfile, 'a') as opened_file:
                # 现在将日志打到指定的文件
                opened_file.write(log_string + '\n')
            # 现在,发送一个通知
            self.notify()
            return func(*args, **kwargs)
        return wrapped_function
    def notify(self):
        # logit只打日志,不做别的
        pass
@logit()
def myfunc1():
    pass

6.多层装饰器的嵌套

#装饰器1
def decorator1(func):
    #定义装饰之后的函数
    def wrapper1():
        # 装饰器1
        print('1-----装饰1之前')
        # 调用基本函数
        func()
        # 扩展功能2
        print('1-----装饰1之后')
    return wrapper1
#装饰器2
def decorator2(func):
    #定义装饰之后的函数
    def wrapper2():
        # 装饰器2
        print('2-----装饰2之前')
        # 调用基本函数
        func()
        # 扩展功能2
        print('2-----装饰2之后')
    return wrapper2
#基本函数
@decorator2   # 第二步:test = decorator2(eat) = test2
@decorator1   # 第一步:test = decorator1(eat)  = test1
def test():
    print('测试')
#调用函数
test()

运行结果:

2-----装饰2之前
1-----装饰1之前
测试
1-----装饰1之后
2-----装饰2之后

Process finished with exit code 0

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Python 函数装饰器详解

    目录 使用场景 授权(Authorization) 日志(Logging) 带参数的装饰器 在函数中嵌入装饰器 装饰器类 总结 装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数.他们有助于让我们的代码更简短,也更Pythonic(Python范儿).大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁.首先,让我们讨论下如何写你自己的装饰器. 这可能是最难掌握的概念之一.我们会每次只讨论一个步骤,这样你能

  • python三大器之装饰器详解

    目录 装饰器 总结 装饰器 讲装饰器之前要先了解两个概念: 对象引用 :对象名仅仅只是个绑定内存地址的变量 def func(): # 函数名仅仅只是个绑定内存地址的变量 print("i`m running") # 这是调用 func() # i`m running # 这是对象引用,引用的是内存地址 func2 = func print(func2 is func) # True # 通过引用进行调用 func2() # i`m running 闭包:定义一个函数A,然后在该函数内

  • 详解Python装饰器之@property

    一.property() 函数讲解 了解 @property 装饰器之前,我们首先要了解内置函数的 property(). class property(fget=None, fset=None, fdel=None, doc=None) 描述: 返回 property 属性. 参数说明: fget -- 获取属性值的函数. fset -- 设置属性值的函数. fdel -- 删除属性值函数. doc -- property 属性的文档字符串,如果没有给出 doc,则该 property 将拷贝

  • Python pytest装饰器总结(实例详解)

    几个常用装饰器 pytest.ini 配置文件 例子: [pytest] addopts = -v -s --html=py_test/scripts/report/report.html -p no:warnings --reruns=10 testpaths = ./py_test/scripts python_files= test_rerun.py python_classes = Test* python_function = test* xfail_strict = true add

  • Python语法详解之decorator装饰器

    python 是一门优雅的语言,有些使用方法就像魔法一样.装饰器(decorator)就是一种化腐朽性为神奇的技巧.最近一直都在使用 Tornado 框架,一直还是念念不忘 Flask .Flask 是我最喜欢的 Python 框架,最早被它吸引也是源自它使用装饰器这个语法糖(Syntactic sugar)来做 Router,让代码看上去就感觉甜甜的. Tornado 中的 Router 略显平淡,怀念 Flask 的味道,于是很好奇的想知道 Flask 是如何使用这个魔法.通过阅读 Flas

  • Python装饰器代码详解

    目录 一.理解装饰器 二.装饰器原型 1.不带参数的装饰器 2.带参数的被装饰的函数 3.带参数的装饰器 4.使用类作为装饰器 5.使用对象作为装饰器 6.多层装饰器的嵌套 总结 一.理解装饰器 所有东西都是对象(函数可以当做对象传递) 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. def function_one(): print("测试函数") #可以将一个函数赋值给一个变量,比如 foo =function_one #这里没有在使用小括号,因

  • Python装饰器基础详解

    装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法或者类进行加工.在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果.相对于其它方式,装饰器语法简单,代码可读性高.因此,装饰器在Python项目中有广泛的应用. 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自己编写新的装饰器的更多高级语法. 什么是装饰器 装饰是为函数和类指定管理代码的一种

  • Python 装饰器使用详解

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象. 经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权限校验等场景.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用. 先来看一个简单例子: def now(): print('2017_7_29') 现在有一个新的需求,希望可以记录下函数的执行日志,于是在代码中添加日志代码: def now():

  • python中函数总结之装饰器闭包详解

    1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器就是包装原来的函数,从而在不需要修改原来代码的基础之上,可以做更多的事情. 装饰器语法如下: @deco2 @deco1 def func(arg1,arg2...): pass 这个表示了有两个装饰器的函数,那么表示的含义为:func = deco2(deco1(func)) 无参装饰器语法如下:

  • Python 中闭包与装饰器案例详解

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 1.Python中一切皆对象 这恐怕是学习Python最有用的一句话.想必你已经知道Python中的list, tuple, dict等内置数据结构,当你执行: alist = [1, 2, 3] 时,你就创建了一个列表对象,并且用alist这个变量引用它: 当然你也可以自己定义一个类: class House(object): def __init__(self, are

  • Python实现调度算法代码详解

    调度算法 操作系统管理了系统的有限资源,当有多个进程(或多个进程发出的请求)要使用这些资源时,因为资源的有限性,必须按照一定的原则选择进程(请求)来占用资源.这就是调度.目的是控制资源使用者的数量,选取资源使用者许可占用资源或占用资源. 在操作系统中调度是指一种资源分配,因而调度算法是指:根据系统的资源分配策略所规定的资源分配算法.对于不同的的系统和系统目标,通常采用不同的调度算法,例如,在批处理系统中,为了照顾为数众多的段作业,应采用短作业优先的调度算法:又如在分时系统中,为了保证系统具有合理

  • Python模块文件结构代码详解

    本文研究的主要是Python模块文件结构的相关内容,具体如下. Python文件结构 文件结构(范例全文) #/usr/bin/env python "this is a test module" import sys import os debug = True class FooClass (object): "Foo class" pass def test(): "test function" foo = FooClass() if de

  • python装饰器代码深入讲解

    python装饰器就是用于扩展原函数功能的一种函数,这个函数特殊的地方就是它的返回值也是一个函数,使用Python装饰器的一个好处就是:在不需要修改原函数代码的情况下,给函数增加新的功能. 先来看个例子: def say(): print('Nice day') say() # 这个函数的输出为: Nice day 现在,我想在输出Nice day的前面再打印一行****************,类似下面的效果: **************** Nice day 一般情况下,我可以修改上面的代

  • Python 装饰器代码解析

    前言: 以往看到我博客的小伙伴可能都知道,我的前言一般都是吐槽和讲废话环节,哈哈哈哈.今天难得休息,最近可真是太忙了,博主已经连续一年都在996了,所以最近没怎么学习新东西,只能回顾以往的旧知识了,上周一起工作的小伙伴扛不住996离职了,我们三人的小团队也正式解散了,哎.原本想着找时间好好整理一个关于关于接口自动化测试或ceph相关的东西.但由于篇幅过长这里目前可能不会着手写这方面东西.其实啊写是很简单的,主要例子难找.哈哈哈哈. 好了回归正题吧.看过我以往博客的小伙伴肯定见我用过@parame

  • python装饰器代码解析

    目录 1.装饰器通用模型 2.多个装饰器装饰的函数执行 3.带参数的装饰器 4.类装饰器 1.装饰器通用模型 def wrapper(fn):     def inner(*args, **kwargs):         ret = fn(*args, **kwargs)         return ret     return inner 装饰器几个关键点: 1.函数可以当参数传递 2.函数可以作为返回值进行返回 3.函数名称可以当成变量一样进行赋值操作 装饰器本质上是个闭包,在不改变原有

随机推荐