为什么需要装饰器?
谁看过关于装饰器的经典解释:
# Декоратор - это функция, ожидающая ДРУГУЮ функцию в качестве параметра
def my_shiny_new_decorator(a_function_to_decorate):
# Внутри себя декоратор определяет функцию-"обёртку".
# Она будет (что бы вы думали?..) обёрнута вокруг декорируемой,
# получая возможность исполнять произвольный код до и после неё.
def the_wrapper_around_the_original_function():
# Поместим здесь код, который мы хотим запускать ДО вызова
# оригинальной функции
print "Я - код, который отработает до вызова функции"
# ВЫЗОВЕМ саму декорируемую функцию
a_function_to_decorate()
# А здесь поместим код, который мы хотим запускать ПОСЛЕ вызова
# оригинальной функции
print "А я - код, срабатывающий после"
# На данный момент функция "a_function_to_decorate" НЕ ВЫЗЫВАЛАСЬ НИ РАЗУ
# Теперь, вернём функцию-обёртку, которая содержит в себе
# декорируемую функцию, и код, который необходимо выполнить до и после.
# Всё просто!
return the_wrapper_around_the_original_function
# Представим теперь, что у нас есть функция, которую мы не планируем больше трогать.
def a_stand_alone_function():
print "Я простая одинокая функция, ты ведь не посмеешь меня изменять?.."
a_stand_alone_function()
# выведет: Я простая одинокая функция, ты ведь не посмеешь меня изменять?..
# Однако, чтобы изменить её поведение, мы можем декорировать её, то есть
# Просто передать декоратору, который обернет исходную функцию в любой код,
# который нам потребуется, и вернёт новую, готовую к использованию функцию:
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#выведет:
# Я - код, который отработает до вызова функции
# Я простая одинокая функция, ты ведь не посмеешь меня изменять?..
# А я - код, срабатывающий после
接下来是一段话:
可能现在我们希望每次调用 a_stand_alone_function 时,调用 a_stand_alone_function_decorated。没有什么比这更简单的了,只需用 my_shiny_new_decorator 返回给我们的函数覆盖 a_stand_alone_function 即可:
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#выведет:
# Я - код, который отработает до вызова функции
# Я простая одинокая функция, ты ведь не посмеешь меня изменять?..
# А я - код, срабатывающий после
那些。在这段之后 - 我们失去了以原始形式调用函数的机会。现在它总是装饰。
问题是,为什么那时需要装饰器?
1)为什么不(如果我们无论如何都失去了原来的功能)只是重写原来的功能?(只需在函数的开头和结尾添加我们需要的代码片段)。像这样:
def a_stand_alone_function():
print "Я - код, который отработает до вызова функции"
print "Я простая одинокая функция, ты ведь не посмеешь меня изменять?.."
print "А я - код, срабатывающий после"
或者,如果附加代码很大并且应该单独保存,那么:
def a_stand_alone_function():
pre_function()
print "Я простая одинокая функция, ты ведь не посмеешь меня изменять?.."
post_function()
2)为什么所有这些混乱,而不是像问题 1 那样提出一个简单的解决方案?
3)如果可以同时调用装饰函数和原始函数,我也会理解装饰器。但是用@写的装饰器不允许这样。为什么装饰器会覆盖原来的功能?
我将非常感谢您提供解释的答案,也许还有来自实际实践的清晰示例。
例如,装饰器在 Django 中被广泛使用。与其重新发明轮子并在每个控制器功能中编写自己的授权检查代码,这应该只对授权用户可用,我们只需使用适当的装饰器对其进行装饰。而如果还需要保证函数只会用于某种类型的请求呢?那所有与数据库打交道的函数都会在一个事务中执行吗?如果所有代码都被拉入一个函数中,那么很快它的原始含义就会在一堆样板代码中消失。但它在模块中并不孤单,对于每个模块,您都必须编写此样板代码,并重复多次。而不仅仅是写:
除了@Sergey Gornostaev的回答:
装饰器本质上是 Python 中面向方面编程的一种实现。
您定义的逻辑或功能与将使用该功能的函数分开。也许另一个团队正在为您开发这个逻辑。您几乎随处可见的日志记录示例或相同的事务是方面功能的可能示例之一。然后您可以轻松地启用此方面的使用,而无需手动重写函数,只需添加或删除一个属性。
在任何情况下,该属性都是您的源代码的一部分。如果你想要一个未修饰的函数可用,你可以简单地省略装饰器。或者有一个单独的未修饰函数,以及调用未修饰函数的单独修饰版本。或者添加装饰器手动贡献的功能(但在这种情况下,如果装饰器发生变化,您将需要更新代码,例如,错误修复;这是常见的代码重复问题。)
装饰器只是让您轻松地添加功能。