python 装饰器装饰类
Python is considered to be a general purpose programming language because of it’s simplified syntax which emphasis on natural language. Hence, it can be used for developing desktop or web-based application. Also, codes in python can be easily written, interpreted and executed much faster than any other language. Apart from this, it provides a huge number of predefined modules and libraries for performing complex and scientific calculations or for any Artificial Intelligence based application.
Python被认为是一种通用的编程语言,因为它的简化语法强调自然语言。 因此,它可以用于开发桌面或基于Web的应用程序。 而且,Python中的代码可以比其他任何语言更容易地编写,解释和执行。 除此之外,它提供了大量预定义的模块和库,用于执行复杂的科学计算或任何基于人工智能的应用程序。
Decorators in python are those useful tools which can enable python developers to modify the behavior of functions without actually modifying the structure of the function. Decorators basically allows us to wrap a function in another function order to extend the behavior of wrapped function, without permanently modifying it.
python中的装饰器是那些有用的工具,可以使python开发人员修改功能的行为而无需实际修改功能的结构。 装饰器基本上允许我们以另一个函数顺序包装函数,以扩展包装函数的行为,而无需永久修改它。
Functions in python supports operations like being passed as an argument, modified, assigned to a variable and returned from a function. This is a fundamental concept to understand, for creating Python decorators. So to understand this, we will create a function that will return the square of the number. We will then assign that function to a variable and use the variable to call the function.
python中的函数支持诸如作为参数传递,修改,分配给变量并从函数返回等操作。 这是创建Python装饰器时要理解的基本概念。 因此,为了理解这一点,我们将创建一个函数,该函数将返回数字的平方。 然后,我们将该函数分配给变量,并使用该变量调用该函数。
def calc_square( number ) : # function calculates square of a number return number**2square = calc_squaresquare(5) # yields 25We will now see how we can define a function within the other function and soon we will find out how all this is relevant with creating and understanding decorators.
现在我们将看到如何在另一个函数中定义一个函数,并且很快我们将发现所有这些与创建和理解装饰器之间的关系。
def wrapper(number): # Outer function def calc_square(number): # Inner function return number**2 return calc_square(number)wrapper(5) # yields 25A function can also define a function within it and return that function as well.
一个函数还可以在其中定义一个函数并返回该函数。
def wrapper(): def calc_square(number): return number**2 return calc_square # inner function is returnedsquare = wrapper()square(5)In the above example, calc_square function is defined within the wrapper function and the wrapper function return the calc_square function. Hence, wrapper function will return a function and square can be calculated by the returned function whenever required.
在上述例子中,calc_square函数包装函数内定义和包装函数返回calc_square功能。 因此,包装器函数将返回一个函数,并且可以在需要时由返回的函数计算平方。
Python allows a nested function to access the variable in the scope of the enclosing function. This is a crucial concept in decorators and this pattern is known as a Closure. The below example will show that inner functions can access the variable from enclosing function’s scope.
Python允许嵌套函数访问封闭函数范围内的变量。 这是装饰器中的关键概念,这种模式称为“关闭” 。 下面的示例将显示内部函数可以从封闭函数的作用域访问变量。
def outer_function(message): def inner_function(): print(message) # yields "Created Closure in Python" # message is a variable from the outer_function's scope inner_function()outer_function("Created Closure in Python")Python also allows to pass functions as parameters to other functions like illustrated below:
Python还允许将函数作为参数传递给其他函数,如下所示:
def print_report(report): print(report)def get_report(function): report = "It is a sunny Day!" function(report) # call to the print_report functionget_report(print_report) # yields "It is a sunny Day!"Now using these above mentioned concepts, we will create a simple decorator that will add a header message for today’s report. We will do this by defining a wrapper inside an enclosing function.
现在,使用上述这些概念,我们将创建一个简单的装饰器,该装饰器将为今天的报告添加标题消息。 我们将通过在封闭函数中定义包装器来实现此目的。
def add_header(function): def with_header(): print("Welcome!") function() return with_headerOur decorator function, that is, add_header function takes a function as an argument. It decorates the argument function in such a way that it prints a welcome message before the function. So, now we need to design a function that prints the weather report. Also, we learnt earlier that we can assign a function to a variable earlier, so we will use that here to call the decorator.
我们的装饰器函数(即add_header函数)将一个函数作为参数。 它以一种在函数之前打印欢迎消息的方式修饰参数函数。 因此,现在我们需要设计一个打印天气报告的功能。 另外,我们较早地了解到我们可以更早地将函数分配给变量,因此我们将在此处使用它来调用装饰器。
def print_report(): print("It is a rainy day.")decorate = add_header(print_report)decorate()Now, python provides a much easier way for us to apply decorators. Simply using @ symbol prior to the function we would like to decorate, like illustrated below:
现在,python为我们提供了应用装饰器的简便得多的方法。 只需在我们要装饰的函数之前使用@符号,如下图所示:
@add_headerdef print_report(): print("It is a rainy day.")print_report()# Welcome!# It is a rainy day.Now, what actually is happening on using the decorators is:
现在,使用装饰器实际发生的是:
As soon as python interpreter encounter this @ symbol, it modifies the function on which it has been applied to. If @ symbol was not in existence, then print_report function would be simply pointing to the instance of function that only prints a single message, that is the one we defined. Now, if @ symbol is used, then print_report function would point to the instance of a modified function that the decorator function returned, that is the one with welcome message.
一旦python解释器遇到此@符号,它将修改其应用到的函数。 如果不存在@符号,则print_report函数将仅指向仅打印一条消息(即我们定义的一条消息)的函数实例。 现在,如果使用@符号,则print_report函数将指向修饰器函数返回的已修改函数的实例,即带有欢迎消息的实例。
So now after applying the @ symbol, when we called the print_report function, which is not same anymore as we defined but have been modified is called, and we see our report decorated with a header message.
因此,现在在应用@符号之后,当我们调用print_report函数时,该函数不再与我们定义的功能相同,但已被修改,并且将看到报告以标头消息修饰。
Now, we will try to apply multiple decorators to our function, that is, one will add header to our weather report and another would add footer. However, the decorators will be applied in the order that we’ve called them.
现在,我们将尝试对我们的函数应用多个装饰器,即,一个将添加页眉到天气报告中,另一个将添加页脚。 但是,装饰器将按照我们称为装饰器的顺序进行应用。
# Another decorator function for footerdef add_footer(function): def with_footer(): function() print("Thank You!") return with_footerNow, applying both of them to our function:
现在,将它们都应用到我们的函数中:
@add_footer@add_headerdef print_report(): print("It is a rainy day.")print_report()# Welcome!# It is a rainy day.# Thank You!From the above output, we notice that the application of decorators is from the bottom up. For this the decorators must have been stored in some kind of data structures that follow, Last in First Out principle, as first the footer decorator would have been pushed and then the header one. And while decorating, the header one is decorated prior to the footer one. So, this is the proof of concept for LIFO principle.
从上面的输出中,我们注意到装饰器的应用是自下而上的。 为此,必须将装饰器存储在遵循“后进先出”原则的某种数据结构中,因为首先将先推动页脚装饰器,然后再推动页眉装饰器。 在装饰时,页眉一在页脚一之前被装饰。 因此,这就是LIFO原理的概念证明。
Also, in this case the output won’t be affected if the decorators are interchanged, because of the programming done in the decorator functions. But in other cases, interchanging the order could diversely affect the output.
同样,在这种情况下,如果装饰器互换,则输出不会受到影响,这是因为装饰器函数已完成编程。 但是在其他情况下,互换顺序可能会影响输出。
Often we might need to define a decorator that accepts arguments. We can achieve this by passing the arguments to the wrapper function. The arguments will then be passed to the function that is being decorated at call time. Better illustration is given below:
通常,我们可能需要定义一个接受参数的装饰器。 我们可以通过将参数传递给wrapper函数来实现。 然后,参数将传递给调用时正在修饰的函数。 下面给出了更好的说明:
def add_header(function): def with_header(weather): print("Welcome!") function(weather) return with_header@add_headerdef print_report(weather): print("It is a {0} day.".format(weather))print_report('Rainy')# Welcome!# It is a Rainy day.To define a general purpose decorator that can be applied to any function, we need to use *args and **kargs. These will collect all positional and keyword arguments and stores them in the variables respectively. Also, these allows us to pass variable number of arguments during function calls.
要定义可应用于任何功能的通用装饰器,我们需要使用* args和** kargs。 这些将收集所有位置和关键字参数,并将它们分别存储在变量中。 而且,这些允许我们在函数调用期间传递可变数量的参数。
Now let’s see how we can pass arguments to the decorator itself. In order to achieve this, we define a decorator maker that accepts arguments then define a decorator inside it, which would be the actual decorator and then we will define a wrapper function inside the decorator as we did earlier.
现在让我们看看如何将参数传递给装饰器本身。 为了实现这一点,我们定义了一个装饰器制造商,该制造器接受参数,然后在其中定义一个装饰器,该装饰器将是实际的装饰器,然后像前面所做的那样在该装饰器中定义一个包装函数。
def add_header(heading): def actual_header_adder(function): def with_header(message): print(heading) function(message) return with_header return actual_header_adder@add_header("Weather Report")def print_report(message): print("It will be a {0} day.".format(message))print_report("Rainy")# Weather Report# It will be a Rainy day.In this article, we learnt about the concept of decorators. Decorators dynamically alter the functionality of a function or class without directly change the source code of the function or class being decorated. Using decorators in Python, one can also ensure the code doesn’t repeat unnecessarily. Hope you find it helpful and feel free to add comments/notes for any suggestions or questions.
在本文中,我们了解了装饰器的概念。 装饰器动态更改功能或类的功能,而无需直接更改要修饰的功能或类的源代码。 使用Python中的装饰器,还可以确保代码不会不必要地重复。 希望对您有所帮助,并随时为任何建议或问题添加评论/注释。
Thank You!
谢谢!
翻译自: https://medium.com/@prayukti/decorators-in-python-dbd35c32c00a
python 装饰器装饰类
相关资源:基于Python 装饰器装饰类中的方法实例