Python 简明教程
Python - Decorators
Python 中的装饰器是一个接收另一个函数作为参数的函数。装饰器要装饰的参数函数。装饰器扩展了参数函数的行为,而不会实际修改它。
A Decorator in Python is a function that receives another function as argument. The argument function is the one to be decorated by decorator. The behaviour of argument function is extended by the decorator without actually modifying it.
在本章中,我们 whall 将学习如何使用 Python 装饰器。
In this chapter, we whall learn how to use Python decorator.
Defining Function Decorator
Function in Python 是一个一阶对象。这意味着它可以作为参数传递给另一个函数,就像其他 data types (例如数字、字符串或列表等)。还可以在另一个函数中定义一个函数。这样的函数称为嵌套函数。此外,函数还可以返回其他函数。
Function in Python is a first order object. It means that it can be passed as argument to another function just as other data types such as number, string or list etc. It is also possible to define a function inside another function. Such a function is called nested function. Moreover, a function can return other function as well.
装饰器函数的典型定义如下 −
The typical definition of a decorator function is as under −
def decorator(arg_function): #arg_function to be decorated
def nested_function():
#this wraps the arg_function and extends its behaviour
#call arg_function
arg_function()
return nested_function
此处为一个普通的 Python 函数 −
Here a normal Python function −
def function():
print ("hello")
你现在可以通过将该函数传递给装饰器来装饰它以扩展其行为 −
You can now decorate this function to extend its behaviour by passing it to decorator −
function=decorator(function)
如果现在执行此函数,它将显示装饰器扩展的输出。
If this function is now executed, it will show output extended by decorator.
Examples of Python Decorators
练习以下示例来理解 Python 装饰器的概念 −
Practice the following examples to understand the concept of Python decorators −
Example 1
以下代码是装饰器的简单示例 −
Following code is a simple example of decorator −
def my_function(x):
print("The number is=",x)
def my_decorator(some_function,num):
def wrapper(num):
print("Inside wrapper to check odd/even")
if num%2 == 0:
ret= "Even"
else:
ret= "Odd!"
some_function(num)
return ret
print ("wrapper function is called")
return wrapper
no=10
my_function = my_decorator(my_function, no)
print ("It is ",my_function(no))
my_function() 刚输出接收到的数字。但是,通过将它传递给 my_decorator 来修改其行为。内部函数接收数字并返回它是奇数/偶数。上面代码的输出为 −
The my_function() just prints out the received number. However, its behaviour is modified by passing it to a my_decorator. The inner function receives the number and returns whether it is odd/even. Output of above code is −
wrapper function is called
Inside wrapper to check odd/even
The number is= 10
It is Even
Example 2
装饰函数的一种优雅方式是在其定义之前只提一下装饰器名前面加上 @ 符号。上面的例子使用这种符号重写了 −
An elegant way to decorate a function is to mention just before its definition, the name of decorator prepended by @ symbol. The above example is re-written using this notation −
def my_decorator(some_function):
def wrapper(num):
print("Inside wrapper to check odd/even")
if num%2 == 0:
ret= "Even"
else:
ret= "Odd!"
some_function(num)
return ret
print ("wrapper function is called")
return wrapper
@my_decorator
def my_function(x):
print("The number is=",x)
no=10
print ("It is ",my_function(no))
Python 的标准库定义了以下内置装饰器 −
Python’s standard library defines following built-in decorators −
@classmethod Decorator
classmethod 是一个内置函数。它将方法转换为类方法。类方法不同于实例方法。在类中定义的实例方法由其对象调用。该方法接收由 self 引用的隐式对象。另一方面,类方法隐式地将类本身作为第一个参数接收。
The classmethod is a built-in function. It transforms a method into a class method. A class method is different from an instance method. Instance method defined in a class is called by its object. The method received an implicit object referred to by self. A class method on the other hand implicitly receives the class itself as first argument.
Syntax
为了声明类方法,使用了以下装饰器符号 −
In order to declare a class method, the following notation of decorator is used −
class Myclass:
@classmethod
def mymethod(cls):
#....
@classmethod 表单是前面描述的函数装饰器的形式。mymethod 接收对类的引用。它可以由类及其对象调用。这意味着 Myclass.mymethod 和 Myclass().mymethod 都是有效的调用。
The @classmethod form is that of function decorator as described earlier. The mymethod receives reference to the class. It can be called by the class as well as its object. That means Myclass.mymethod as well as Myclass().mymethod both are valid calls.
Example of @classmethod Decorator
让我们在以下示例的帮助下了解类方法的行为−
Let us understand the behaviour of class method with the help of following example −
class counter:
count=0
def __init__(self):
print ("init called by ", self)
counter.count=counter.count+1
print ("count=",counter.count)
@classmethod
def showcount(cls):
print ("called by ",cls)
print ("count=",cls.count)
c1=counter()
c2=counter()
print ("class method called by object")
c1.showcount()
print ("class method called by class")
counter.showcount()
在类定义中 count 是一个类属性。 init () 方法是构造器,显然是实例方法,因为它接收了 self 作为对象引用。声明的每个对象都会调用此方法,并将计数增加 1。
In the class definition count is a class attribute. The init() method is the constructor and is obviously an instance method as it received self as object reference. Every object declared calls this method and increments count by 1.
@classmethod 装饰器将 showcount() 方法转换为类方法,该方法接收对该类的引用作为参数,即使它是由其对象调用的。即使当 c1 对象调用 showcount 时,它也会显示 counter 类的引用。
The @classmethod decorator transforms showcount() method into a class method which receives reference to the class as argument even if it is called by its object. It can be seen even when c1 object calls showcount, it displays reference of counter class.
它将显示以下内容 output −
It will display the following output −
init called by <__main__.counter object at 0x000001D32DB4F0F0>
count= 1
init called by <__main__.counter object at 0x000001D32DAC8710>
count= 2
class method called by object
called by <class '__main__.counter'>
count= 2
class method called by class
called by <class '__main__.counter'>
@staticmethod Decorator
staticmethod 也是 Python 标准库中的一个内置函数。它会将一个方法转换为一个静态方法。即使是通过类或类的实例调用的,静态方法也不接受任何引用参数。以下是在类中声明静态方法的符号说明−
The staticmethod is also a built-in function in Python standard library. It transforms a method into a static method. Static method doesn’t receive any reference argument whether it is called by instance of class or class itself. Following notation used to declare a static method in a class −
Syntax
class Myclass:
@staticmethod
def mymethod():
#....
即使 Myclass.mymethod 和 Myclass().mymethod 都是有效的调用,但静态方法都不会接收到对 two 的引用。
Even though Myclass.mymethod as well as Myclass().mymethod both are valid calls, the static method receives reference of neither.
Example of @staticmethod Decorator
counter 类进行修改如下−
The counter class is modified as under −
class counter:
count=0
def __init__(self):
print ("init called by ", self)
counter.count=counter.count+1
print ("count=",counter.count)
@staticmethod
def showcount():
print ("count=",counter.count)
c1=counter()
c2=counter()
print ("class method called by object")
c1.showcount()
print ("class method called by class")
counter.showcount()
和以前一样,类属性 count 在 init () 方法中声明每个对象后增加。但是,由于 mymethod() 是一个静态方法,它既不接受 self 参数也不接受 cls 参数。因此,显示类属性 count 的值时,必须显式引用 counter。
As before, the class attribute count is increment on declaration of each object inside the init() method. However, since mymethod(), being a static method doesn’t receive either self or cls parameter. Hence value of class attribute count is displayed with explicit reference to counter.
以上代码的 output 如下−
The output of the above code is as below −
init called by <__main__.counter object at 0x000002512EDCF0B8>
count= 1
init called by <__main__.counter object at 0x000002512ED48668>
count= 2
class method called by object
count= 2
class method called by class
count= 2
@property Decorator
Python 的 property() 内置函数是用于访问类的实例变量的一个接口。@property 装饰器将实例方法转换为同名只读属性的“getter”(获得器),并且它将此属性的文档字符串设置为“获取实例变量的当前值”。
Python’s property() built-in function is an interface for accessing instance variables of a class. The @property decorator turns an instance method into a "getter" for a read-only attribute with the same name, and it sets the docstring for the property to "Get the current value of the instance variable."
您可以使用以下三个装饰器来定义属性−
You can use the following three decorators to define a property −
-
@property − Declares the method as a property.
-
@<property-name>.setter: − Specifies the setter method for a property that sets the value to a property.
-
@<property-name>.deleter − Specifies the delete method as a property that deletes a property.
property() 函数返回的属性对象具有 getter、setter 和 delete 方法。
A property object returned by property() function has getter, setter, and delete methods.
property(fget=None, fset=None, fdel=None, doc=None)
fget 参数是 getter 方法,fset 是 setter 方法。它还可以选择性地使用 fdel 作为删除对象的方法,而 doc 是文档字符串。
The fget argument is the getter method, fset is setter method. It optionally can have fdel as method to delete the object and doc is the documentation string.
Syntax
还可以使用以下语法为 property() 对象的 setter 和 getter 赋值。
The property() object’s setter and getter may also be assigned with the following syntax also.
speed = property()
speed=speed.getter(speed, get_speed)
speed=speed.setter(speed, set_speed)
其中 get_speed() 和 set_speeds() 是在 Car 类中检索和设置实例变量 speed 的值的方法。
Where get_speed() and set_speeds() are the instance methods that retrieve and set the value to an instance variable speed in Car class.
可以通过 @property 装饰器实现上述语句。使用装饰器后,重新编写的 car 类如下−
The above statements can be implemented by @property decorator. Using the decorator car class is re-written as −
Example of @property Decorator
class car:
def __init__(self, speed=40):
self._speed=speed
return
@property
def speed(self):
return self._speed
@speed.setter
def speed(self, speed):
if speed<0 or speed>100:
print ("speed limit 0 to 100")
return
self._speed=speed
return
c1=car()
print (c1.speed) #calls getter
c1.speed=60 #calls setter
属性装饰器是一种非常方便且推荐的实例属性处理方法。
Property decorator is very convenient and recommended method of handling instance attributes.