Python装饰器代码详解

作者:凡晨丹心 时间:2021-04-28 23:16:03 

一、理解装饰器

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


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

来源:https://blog.csdn.net/Michaelyq1229/article/details/120941215

标签:Python,装饰器,详解
0
投稿

猜你喜欢

  • JDBC获取数据库连接的5种方式实例

    2024-01-19 05:14:05
  • python 数据的清理行为实例详解

    2021-04-12 08:43:50
  • Vue项目中如何使用Axios封装http请求详解

    2024-04-28 09:19:49
  • 一个简单的python程序实例(通讯录)

    2023-05-16 06:49:11
  • python实现爬虫统计学校BBS男女比例之数据处理(三)

    2022-12-11 18:56:45
  • 简介Django框架中可使用的各类缓存

    2022-01-16 13:02:39
  • python主线程与子线程的结束顺序实例解析

    2023-10-09 12:46:07
  • Python一阶马尔科夫链生成随机DNA序列实现示例

    2021-06-23 07:42:22
  • python机器学习之贝叶斯分类

    2023-10-16 00:31:28
  • 表单设计中的网页视觉体验

    2008-06-26 13:35:00
  • 浅谈MySQL中的自增主键用完了怎么办

    2024-01-24 07:51:50
  • Python 相对路径和绝对路径及写法演示

    2023-01-17 15:23:07
  • 快速创建python 虚拟环境

    2023-10-04 08:58:31
  • 在PyCharm中批量查找及替换的方法

    2023-05-29 17:15:13
  • Python getattr()函数使用方法代码实例

    2022-03-04 03:30:51
  • Python将阿拉伯数字转换为罗马数字的方法

    2022-11-15 16:07:14
  • 教你如何使Python爬取酷我在线音乐

    2021-02-18 14:13:01
  • 解说mysql之binlog日志以及利用binlog日志恢复数据的方法

    2024-01-28 08:39:57
  • Python中生成一个指定长度的随机字符串实现示例

    2023-02-16 21:46:07
  • Python 正则表达式匹配字符串中的http链接方法

    2022-02-11 03:02:13
  • asp之家 网络编程 m.aspxhome.com