装饰器

常见的3种装饰器@property、@staticmethod、@classmethod的作用:

  1、  @property 装饰过的函数返回的不再是一个函数,而是一个property对象装饰过后的方法不再是可调用的对象,可以看做数据属性直接访问。

示例代码:

class Rectangle:
    def __init__(self,width,height):
        self.width = width
        self.height = height
        
    def area(self):
        return self.width*self.height

    def __add__(self,other):
        if isinstance(other,Rectangle):
            return self.area()+other.area()

C1 = Rectangle(3,4)

#输出结果:
==================== RESTART: D:/Python36/note/装饰器002.py ====================
>>> C1.area()
12
>>> C1.area
<bound method Rectangle.area of <__main__.Rectangle object at 0x0000000002B38550>>
>>> C1.width
3
>>> C1.height
4
>>> 

在用没有使用装饰器时候,类中的方法和属性用上述方式调用,接下来用装饰器@property来装饰方法area

 1 class Rectangle:
 2     def __init__(self,width,height):
 3         self.width = width
 4         self.height = height
 5         
 6     @property
 7     def area(self):
 8         return self.width*self.height
 9 
10     def __add__(self,other):
11         if isinstance(other,Rectangle):
12             return self.area()+other.area()
13 
14 C1 = Rectangle(3,4)
15 
16 #输出结果:
17 >>> C1.area
18 12
19 >>> C1.area()
20 Traceback (most recent call last):
21   File "<pyshell#134>", line 1, in <module>
22     C1.area()
23 TypeError: 'int' object is not callable
24 >>> C1.height
25 4
26 >>> C1.width
27 3
28 >>> 

通过用装饰器@property装饰之后,类中的方法area可以用原来调用属性的方式进行调用,而用方法本身调用的方式反而报错,这说明装饰器将类中的方法变成了一种属性

2、@staticmethod 把没有参数的函数装饰过后变成可被实例调用的函数,函数定义时是没有参数的。

 1 class Rectangle:
 2     def __init__(self,width,height):
 3         self.width = width
 4         self.height = height
 5         
 6     @property
 7     def area(self):
 8         return self.width*self.height
 9 
10     def __add__(self,other):
11         if isinstance(other,Rectangle):
12             return self.area()+other.area()
13 
14     def fun():
15         return '没有参数的函数输出'
16 
17 C1 = Rectangle(3,4)
18 
19 #输出结果:
20 >>> C1.fun
21 <bound method Rectangle.fun of <__main__.Rectangle object at 0x0000000002B386D8>>
22 >>> C1.fun()
23 Traceback (most recent call last):
24   File "<pyshell#142>", line 1, in <module>
25     C1.fun()
26 TypeError: fun() takes 0 positional arguments but 1 was given
27 >>> 

 从上面的代码中可以发现没有类中没有参数的函数fun虽然可以直接通过类名.函数名来访问,但是输出的对象不能容易识别的内容,而直接通过类名.函数名()就会报错,这里通过静态方法@staticmethod来装饰一下,再继续看效果:

class Rectangle:
    def __init__(self,width,height):
        self.width = width
        self.height = height
        
    @property
    def area(self):
        return self.width*self.height

    def __add__(self,other):
        if isinstance(other,Rectangle):
            return self.area()+other.area()
    @staticmethod
    def fun():
        return '没有参数的函数输出'

C1 = Rectangle(3,4)

#输出结果:
>>> C1.fun
<function Rectangle.fun at 0x0000000002DCF840>
>>> C1.fun()
'没有参数的函数输出'
>>> 

3、@classmethod 把装饰过的方法变成一个classmethod类对象,既能被类调用又能被实例调用。注意参数是cls代表这个类本身。而是用实例的方法只能被实例调用。

  

class Rectangle:
    def __init__(self,width,height):
        self.width = width
        self.height = height
        
    @property
    def area(self):
        return self.width*self.height

    def __add__(self,other):
        if isinstance(other,Rectangle):
            return self.area()+other.area()
        
    @staticmethod
    def fun():
        return '没有参数的函数输出'

    
    def show():
        return '类方法返回值'

C1 = Rectangle(3,4)

#调用show方法输出结果:
>>> Rectangle.show
<function Rectangle.show at 0x0000000002BCF8C8>
>>> Rectangle.show()
'类方法返回值'
>>> C1.show
<bound method Rectangle.show of <__main__.Rectangle object at 0x0000000002B38710>>
>>> C1.show()
Traceback (most recent call last):
  File "<pyshell#177>", line 1, in <module>
    C1.show()
TypeError: show() takes 0 positional arguments but 1 was given
>>> 

类直接调用show方法是可以的,但是通过实例C1调用则发现报错,这里我们通过装饰器@classmethod装饰后,再看效果:

 1 class Rectangle:
 2     def __init__(self,width,height):
 3         self.width = width
 4         self.height = height
 5         
 6     @property
 7     def area(self):
 8         return self.width*self.height
 9 
10     def __add__(self,other):
11         if isinstance(other,Rectangle):
12             return self.area()+other.area()
13         
14     @staticmethod
15     def fun():
16         return '没有参数的函数输出'
17 
18     @classmethod
19     def show(cls):
20         return '类方法返回值'
21 
22 C1 = Rectangle(3,4)
23 
24 #调用show方法输出结果:
25 >>> Rectangle.show
26 <bound method Rectangle.show of <class '__main__.Rectangle'>>
27 >>> Rectangle.show()
28 '类方法返回值'
29 >>> C1.show
30 <bound method Rectangle.show of <class '__main__.Rectangle'>>
31 >>> C1.show()
32 '类方法返回值'
33 >>> 

发现通过装饰器@classmethod装饰后,show方法不仅可以被类直接调用,而且也可以被对象C1调用,证明了@classmethod装饰器能将类中的方法转换成既能被类调用也能被示例调用

4、内嵌函数(闭包)

def fun1(x):
    def fun2(y):
        return x*y
    return fun2

#运行结果:
>>> fun1(2)
<function fun1.<locals>.fun2 at 0x0000000001CF3E18>
>>> fun1(2)(3)
6
>>> fun1(2)
<function fun1.<locals>.fun2 at 0x0000000001CF3E18>
>>> 

函数fun1运行后返回的值是另外一个函数fun2,即:<function fun1.<locals>.fun2 at 0x0000000001CF3E18>,接着在该对象后面继续赋值?(3),即调用函数fun2(3)此时返回 x*y的值,所以此时最终返回值为6,即从外面外里面传参数,然后把里面函数结果返回到外面,这就是闭包,整体的结构中fun2就是内嵌函数。

原文地址:https://www.cnblogs.com/kindnull/p/6813149.html