博客
关于我
python语言:装饰器原理
阅读量:796 次
发布时间:2023-03-06

本文共 4558 字,大约阅读时间需要 15 分钟。

装饰器(Decorator)是 Python 中一个强大的功能,能够在不修改函数代码的情况下,动态地扩展函数的行为。它们广泛应用于代码的简洁化、权限管理、日志记录等领域。本文将从基础到高级讲解装饰器的使用方法及其实际应用场景。

1. 函数也是对象

在开始学习装饰器之前,首先需要明确一个关键概念:函数是对象。这意味着函数可以被赋值给变量,或者在另一个函数中被定义和调用。例如:

def hi(name="yasoob"):
return "hi " + name
# 调用函数并将结果输出
print(hi()) # 输出: 'hi yasoob'

函数也可以作为变量赋值:

greet = hi
print(greet()) # 输出: 'hi yasoob'

这表明函数不仅可以被调用,还可以被用作变量,具备对象的属性。

2. 函数的嵌套与返回

在函数内部,可以定义另一个函数,并通过返回该函数来实现功能的延迟。例如:

def hi(name="yasoob"):
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
print(greet()) # 输出: now you are in the greet() function
print(welcome()) # 输出: now you are in the welcome() function

如果在外部调用 greet(),则会抛出 NameError,这表明 greet() 函数仅在 hi() 函数内部可用。

3. 函数作为返回值

为了更加灵活地使用函数,可以将其作为返回值。例如:

def hi(name="yasoob"):
if name == "yasoob":
return greet
else:
return welcome
# 调用并执行
a = hi()
print(a()) # 输出: now you are in the greet() function

这里,hi() 根据 name 的值返回 greet()welcome() 函数,并在调用 a() 时执行返回的函数。

4. 装饰器的核心原理

通过上述示例,可以看出装饰器的核心原理是:在函数执行前或执行后,插入自定义的代码逻辑。例如:

def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
# 使用装饰器
def a_function_requiring_decoration():
print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration() # 输出: I am the function which needs some decoration...
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
a_function_requiring_decoration() # 输出: I am doing some boring work before executing a_func()

5. 使用 @ 装饰符

在 Python 中,装饰符 @ 是一个简洁的语法糖,用于将装饰器应用到函数上。例如:

@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to remove my foul smell")

这与直接赋值的方式等价:

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

6. 高级装饰器应用

装饰器在实际应用中可以用于多种场景,例如权限管理、日志记录等。以下是一个简单的权限管理装饰器示例:

from functools import wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated

7. 装饰器的参数化

装饰器可以接受参数来定制行为。例如,一个带有日志文件路径的日志装饰器:

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)
with open(logfile, 'a') as opened_file:
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator

8. 类装饰器

除了函数装饰器,类也可以用作装饰器。例如,一个带有日志文件和通知功能的类装饰器:

class logit(object):
_logfile = 'out.log'
def __init__(self, func):
self.func = func
def __call__(self, *args):
log_string = self.func.__name__ + " was called"
print(log_string)
with open(self._logfile, 'a') as opened_file:
opened_file.write(log_string + '\n')
self.notify()
def notify(self):
pass

9. 自定义装饰器

通过继承和扩展,可以创建更灵活的装饰器。例如,一个带有电子邮件通知的日志装饰器:

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

10. 综合应用

装饰器的实际应用场景无处不在。例如,在 Flask Web 框架中,常常使用装饰器来管理路由、权限和日志。以下是一个简单的日志记录和权限管理装饰器的组合使用示例:

from functools import wraps
from flask import request, redirect, url_for
import logging
logging.basicConfig(filename='app.log', level=logging.INFO)
def log_request(func):
@wraps(func)
def wrapped(*args, **kwargs):
logging.info(f"访问路径: {request.path}")
return func(*args, **kwargs)
return wrapped
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
if not request.is_authenticated:
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated
@app.route('/')
@log_request
@requires_auth
def home():
return "你好,欢迎访问我们的主页"

11. 常见错误与解决方案

在实际使用装饰器时,可能会遇到以下问题:

  • 装饰器名称冲突:确保装饰器名称唯一,避免与内置函数或其他模块冲突。
  • 装饰器函数名称丢失:使用 functools.wraps 保留函数属性。
  • 装饰器不生效:确保装饰器函数正确应用于目标函数。
  • 12. 最佳实践

  • 使用 functools.wraps:保留函数的原始属性(如名称、文档字符串等)。
  • 保持装饰器简洁:避免过度复杂化,保持代码可读性。
  • 测试装饰器:确保装饰器在不同场景下都能正常工作。
  • 通过以上知识和实践,您可以开始在自己的项目中灵活运用装饰器,提升代码的可维护性和可读性。

    转载地址:http://kdofk.baihongyu.com/

    你可能感兴趣的文章
    Python 中 PIL 读取图片出现异常旋转的解决方法
    查看>>
    python读取word表格内容(1)
    查看>>
    python 中os.path.join 双斜杠的解决办法
    查看>>
    python 中PIL.Image和OpenCV图像格式相互转换
    查看>>
    Python 中Semaphore 信号量对象、Event事件、Condition
    查看>>
    python 中with的使用及样例
    查看>>
    python读取wav文件并播放[pyaudio/wave]
    查看>>
    python读取txt文件的行数
    查看>>
    Python 中内置的最大堆 API
    查看>>
    Python 中只有一个 True 和一个 False 对象吗?
    查看>>
    python读取mtcars数据集并实现以下操作_关于数据处理。。,Python交流,技术交流区,鱼C论坛 - Powered by Discuz!...
    查看>>
    Python 中多线程与多处理之间的区别
    查看>>
    Python 中如何使用 lambda 函数
    查看>>
    Python 中如何创建多行字符串?
    查看>>
    Python 中如何处理异常?
    查看>>
    Python 中如何实现列表的切片?
    查看>>
    Python 中如何实现字典的排序?
    查看>>
    Python 中常用的数据类型及相关操作详解
    查看>>
    python 中文乱码
    查看>>
    Python 中生成器与普通函数的区别
    查看>>