常见的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就是内嵌函数。