装饰器python3菜鸟教程_认识Python装饰器

Python中的装饰器用来给Python中的函数添加一些辅助功能。比如我们可以把【输出日志】这个辅助功能写到一个装饰器里。只要我们在某个函数A之前添加了这个【输出日志】的装饰器,那么执行函数A的时候,就会自动地把关于函数A的日志输出出来。

这篇文章我们会一起学习Python装饰器的原理和使用方法,再进入装饰器的正题之前,我们先来回顾一些Python中的相关知识。

本文纲要预备知识将一个函数赋给一个变量

在函数中定义函数

在函数中返回函数

将函数作为参数传给另一个函数

装饰器的基本说明创建我们第一个装饰器

使用@符号来装饰一个函数

使用场景介绍(日志)

装饰器的拓展说明带参数的装饰器

装饰器类

在同一个函数上定义多个装饰器

参考资料

预备知识

将一个函数赋给一个变量

Python是一门面向对象的语言。在Python中,我们可以把函数当成对象来赋给某个变量。

# 定义一个函数hi

def hi(name="joey"):

return "hi " + name

# 将函数hi赋值给一个变量greet。

# 我们这里没有在使用小括号,因为我们并不是在调用hi函数

# 而是在将它放在greet变量里头。

greet = hi

print(greet())

# output:hi joey

在函数中定义函数

在Python中,我们可以在一个函数中定义另一个函数。

# 在函数中定义函数

def hi():

print("hi function begin.")

def greet2():

return "greet2 function."

def welcome():

return "welcome function."

print(greet2())

print(welcome())

print("hi function end.")

# 执行hi函数。

hi()

# output:

# hi function begin.

# greet2 function.

# welcome function.

# hi function end.

# 函数内的函数不能被直接访问到。

# 执行下面的方法时系统会报错。

greet2()

在函数中返回函数

在Python中,我们可以把函数当成返回值来返回。

# 我们将一个函数A放在另一个函数B当中,

# 并且把函数A作为函数B的返回值返回。

def hi(name="joey"):

# 定义greet子函数。

def greet():

return "greet function"

# 定义welcome子函数。

def welcome():

return "welcome function"

# 在if/else语句中,我们返回greet和welcome函数,

# 而不是greet()和welcome()。

# 因为加上小括号之后,这个函数就会被执行;

# 而不加小括号的时候,函数本身就会被传递出去。

if name == "joey":

return greet

else:

return welcome

将函数作为参数传给另一个函数

在Python中,我们还可以把函数作为一个另一个函数的参数来使用。

# 创建一个普通的函数hi。

def hi():

return "hi joey!"

# 创建一个以函数作为参数的函数doSomethingBeforeFunc。

def doSomethingBeforeFunc(func):

print("Do something before func.")

print(func())

# 把hi函数作为参数传递给doSomethingBeforeFunc函数。

doSomethingBeforeFunc(hi)

# output:

# Do something before func.

# hi joey!

装饰器中大概用到的知识点就是上面这些了。下面我们开始正式学习装饰器的内容。

装饰器的基本说明

创建我们第一个装饰器

Python中的装饰器主要用来补充或者优化某个函数的功能,也就是在某个函数执行之前或者执行之后加上一些操作。比如下面这个例子:

# 创建一个装饰器a_new_decorator,

# 并把某个要被装饰的函数当成参数(a_func)传递到这个装饰器里。

def a_new_decorator(a_func):

def wrapTheFunction():

# 在原函数执行之前补上一些操作。

print("Do something before a_func().")

# 执行原函数。

a_func()

# 在原函数执行之后加上一些操作。

print("Do something after a_func().")

# 把被装饰过得函数作为返回值来返回。

return wrapTheFunction

接下来我们创建一个要被装饰的函数,并且使用上面的装饰器来装饰这个函数。

# 创建一个要被装饰的函数。

def a_function_requiring_decoration():

print("I am the function which needs some decoration.")

# 将上面的函数用a_new_decorator这个函数装饰起来。

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

# 执行被装饰之后的函数

a_function_requiring_decoration()

# output:

# Do something before a_func().

# I am the function which needs some decoration.

# Do something after a_func().

使用@符号来装饰一个函数

在上面的例子中,我们通过下面的这句代码来装饰函数。

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

但是这样的写法稍微复杂了一些,在实际应用中,我们通常通过@符号来装饰函数:

# 使用@符号来装饰一个函数

@a_new_decorator

def a_function_requiring_decoration():

print("I am the function which needs some decoration too.")

# 上面的写法等效于下面的3行代码:

# def a_function_requiring_decoration():

# print("I am the function which needs some decoration.")

# a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

# 执行被装饰的函数

a_function_requiring_decoration()

# output:

# Do something before a_func().

# I am the function which needs some decoration too.# Do something after a_func().

可以看到,通过使用@符号,我们简化了装饰器的写法。

但是现在还有一个小问题,函数被装饰器装饰了之后,原函数的名字改变了:

# 我们希望的函数名是a_function_requiring_decoration,

# 但是现在却变成了wrapTheFunction.

print(a_function_requiring_decoration.__name__)

# output:

# wrapTheFunction

此时,我们可以通过functools.wraps这个函数来解决函数名被改变的问题:

# 可以通过functools.wraps这个函数来解决函数名被改变的问题

from functools import wraps

def a_new_decorator(a_func):

# 调用wraps方法,把它作为一个装饰器来使用。

@wraps(a_func)

def wrapTheFunction():

print("Do something before a_func()")

a_func()

print("Do something after a_func()")

return wrapTheFunction

@a_new_decorator

def a_function_requiring_decoration():

print("I am the function which needs some decoration.")

# 此时再输出函数名,我们可以看到它变成了原来的名字。

print(a_function_requiring_decoration.__name__)

# output:

# a_function_requiring_decoration

使用场景介绍(日志)

装饰器可以简化代码,优化程序的处理过程。它可以应用在很多方面,这里简单介绍如何使用装饰器来生成日志。

from functools import wraps

# 创建一个日志装饰器

def logit(func):

@wraps(func)

def with_logging(*args, **kwargs):

print(func.__name__ + "was called.")

return func(*args, **kwargs)

return with_logging

# 生成一个被装饰的加法计算函数。

@logit

def addition_func(x):

return x + x

# 执行被装饰的加法计算函数。

result = addition_func(4)

print("result:{}".format(result))

# output:

# addition_funcwas called.

# result:8

装饰器的拓展说明

带参数的装饰器

我们可以给装饰器的方法里加上参数。带参数的装饰器会比普通的装饰器多一层函数进行包裹,多出来的这一层函数用来传递参数。

我们改写一下上面日志的例子,使得输出的日志能够保存到日志文件当中。

from functools import wraps

# 创建一个带参数logfile的装饰器logit。

# 参数说明:

# logfile: 指定保存日志的文件。

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)

# 打开日志文件,并写入内容

# ‘a’: 打开一个文件用于追加。

# 如果该文件已存在,新的内容将会被写入到已有内容之后。

# 如果该文件不存在,创建新文件进行写入。

with open(logfile, 'a') as opened_file:

opened_file.write(log_string + '\n')

return func(*args, **kwargs)

return wrapped_function

return logging_decorator

# 创建一个被日志装饰器装饰的函数。

@logit()

def myfunc1():

pass

# 执行下面的函数之后,可以看到当前目录下生成了一个out.log文件。

myfunc1()

# output:

# myfunc1 was called.

装饰器类

上面的例子中,我们把装饰器写成了函数的形式。事实上,我们还可以把装饰器写成类的形式。

把装饰器写成类的形式之后,我们可以很方便地继承这些装饰器类,从而生成功能更多更丰富的装饰器子类。

比如,我们可以把上面的日志装饰器改写成如下的样子:

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):

print("Notify")

pass

# 创建一个被日志装饰器类所装饰的函数。

@logit()

def myfunc3():

pass

# 执行被装饰的函数。

myfunc3()

# output:

# myfunc3 was called.

# Notify.

我们可以继承上面的日志装饰器类,生成一个可以发送邮件的装饰器子类。

# 给上面的logit创建一个子类

class email_logit(logit):

def __init__(self, email='admin@myproject.com', *args, **kwargs):

self.email = email

super(email_logit, self).__init__(*args, **kwargs)

def notify(self):

# 这里可以用来发送一封邮件

pass

# 生成一个被日志装饰器子类装饰的函数。

@email_logit()

def myfunc5():

pass

myfunc5()

# output:

# myfun5 was called.

在同一个函数上定义多个装饰器

我们可以给同一个函数加上多个装饰器,比如下面的样子:

# 一个函数可以同时定义多个装饰器,比如:

@a

@b

@c

def f():

pass

# 它的执行顺序是从里到外,

# 最先调用最里层的装饰器,

# 最后调用最外层的装饰器,它等效于

# f = a(b(c(f)))

以上就是本文的全部内容。

参考资料菜鸟教程-Python函数装饰器本篇文章中出现的代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值