Python 装饰器
在Python中,装饰器是一个以另一个函数作为参数的函数。被装饰器修饰的函数是需要装饰的函数。装饰器通过扩展参数函数的行为来实现装饰,而无需对其进行实际修改。
在本章中,我们将学习如何使用Python装饰器。
Python中的函数是一种一等对象。这意味着它可以像其他数据类型(如数字、字符串或列表等)一样作为参数传递给另一个函数。也可以在另一个函数内定义函数。这样的函数被称为嵌套函数。此外,一个函数也可以返回其他函数。
语法
装饰器函数的典型定义如下所示−
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函数-
def function():
print ("hello")
您现在可以通过将其传递给装饰器来装饰此函数,以扩展其行为。
function=decorator(function)
如果此函数现在执行,将显示由装饰器扩展的输出。
示例1
以下代码是装饰器的简单示例−
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,可以修改其行为。内部函数接收数字并返回奇数/偶数。上述代码的输出为-
wrapper function is called
Inside wrapper to check odd/even
The number is= 10
It is Even
示例2
一个优雅的装饰函数的方式是在其定义之前提到装饰器的名称,并在前面加上@符号。以上例子以这种符号重新编写。
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的标准库定义了以下内置的装饰器 –
@classmethod 装饰器
classmethod是一个内置的函数。它将一个方法转换为类方法。类方法与实例方法不同。在一个类中定义的实例方法通过其对象调用。该方法接收一个被self引用的隐式对象。然而,类方法隐式地将类自身作为第一个参数接收。
语法
为了声明一个类方法,使用以下装饰器的记法 –
class Myclass:
@classmethod
def mymethod(cls):
#....
@classmethod 的形式就像之前描述的函数装饰器。 mymethod 接收到类的引用。它可以被类和类的对象调用。这意味着 Myclass.mymethod 以及 Myclass().mymethod 都是有效的调用。
示例3
让我们通过以下示例来理解类方法的行为:
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递增count。
@classmethod装饰器将showcount()方法转换为一个类方法,即使它是由其对象调用,也会接收类的引用作为参数。甚至当c1对象调用showcount时,它显示计数器类的引用。
它将显示以下内容: 输出 –
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 装饰器
staticmethod也是Python标准库中的一个内置函数。它将一个方法转换为静态方法。静态方法无论是通过类的实例还是类本身调用,都不接收任何引用参数。在类中声明静态方法使用以下语法:
语法
class Myclass:
@staticmethod
def mymethod():
#....
尽管Myclass.mymethod和Myclass().mymethod都是有效的调用,但静态方法都不接收引用。
示例4
计数器类修改如下 –
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()
与之前一样,class属性计数在__init__()
方法中每个对象的声明时递增。然而,由于mymethod()是一个静态方法,不接收self或cls参数。因此,类属性计数的值是通过对计数器的显式引用显示的。
上述代码的输出如下所示−
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”,并将属性的文档字符串设置为”获取实例变量的当前值”。
你可以使用以下三个装饰器来定义一个属性 −
@property
− 将方法声明为一个属性。-
**
@ <property-name>.setter
: ** − 指定一个属性的setter方法,用于设置属性的值。 -
**
@ <property-name>.deleter
** − 指定删除方法作为一个属性,用于删除属性。
由property()函数返回的属性对象具有getter、setter和delete方法。
property(fget=None, fset=None, fdel=None, doc=None)
fget参数是获取方法,fset是设置方法。它还可以选择性地具有fdel作为删除对象的方法,doc是文档字符串。
property()对象的设置器和获取器也可以使用以下语法进行赋值。
speed = property()
speed=speed.getter(speed, get_speed)
speed=speed.setter(speed, set_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类为-
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装饰器是处理实例属性非常方便和推荐的方法。