装饰器是什么?
本质上是一个python函数,它可以让已存在的函数或者对象在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.
有了装饰器,我们可以抽离出大量与函数功能本身无关的雷同代码并继续重用.
def debug(func):
def wrapper():
print "[DEBUG]: enter {}()".format(func.__name__)
return func()
return wrapper
@debug
def say_hello():
print "hello!"
debug函数是一个装饰器,它对原函数say_hello做了包装并返回了另外一个函数,额外添加了一些功能(print出函数的名字)
如果被装饰的函数需要传入参数,可以指定装饰器函数wrapper接受和原函数一样的参数,代码如下
def debug(func):
def wrapper(something): # 指定一毛一样的参数
print "[DEBUG]: enter {}()".format(func.__name__)
return func(something)
return wrapper # 返回包装过函数
@debug
def say(something):
print "hello {}!".format(something)
装饰器可以传入可变参数来适应不同函数需要的参数,使用可变参数*args
和关键字参数**kwargs
,有了这两个参数,装饰器就可以用于任意目标函数了
def debug(func):
def wrapper(*args, **kwargs): # 指定宇宙无敌参数
print "[DEBUG]: enter {}()".format(func.__name__)
print 'Prepare and say...',
return func(*args, **kwargs)
return wrapper # 返回
@debug
def say(something):
print "hello {}!".format(something)
内置装饰器
常用的内置装饰器有三种 @property @staticmethod @classmethod
@property
把类内方法当成属性来使用,必须要有返回值,相当于getter
假如没有定义@func.setter
修饰方法的话,就是只读属性
class Car:
def __init__(self, name, price):
self._name = name
self._price = price
@property
def car_name(self):
return self._name
# car_name 可以读写的属性
@car_name.setter
def car_name(self, value):
self._name = value
# car_price 是只读属性
@property
def car_price(self):
return str(self._price) + '万'
benz = Car('benz', 30)
print(benz.car_name) # benz
benz.car_name = 'baojun'
print(benz.car_name) # baojun
print(benz.car_price) # 30万
@staticmethod
静态方法,不需要表示自身对象的self
和自身类的cls
参数,就和使用函数一样
@classmethod
类方法,不需要self
参数,但第一个参数需要是表示自身类的cls
参数
例子如下
class Demo(object):
text = '三种方法的比较'
def instance_method(self):
print('调用实例方法')
@classmethod
def class_method(cls):
print('调用类方法')
print('在类方法中 访问类属性 text : {}'.format(cls().text))
print('在类方法中, 调用实例方法 instance_method : {}'.format(cls().instance_method()))
@staticmethod
def static_method():
print('调用静态方法')
print('在静态方法中 访问类属性 text: {}'.format(Demo().text))
print('在静态方法中 调用实例方法 instance_method : {}'.format(Demo().instance_method()))
# 实例化对象
d = Demo()
# 对象可以访问 实例方法,类方法,静态方法
# 通过对象访问text属性
print(d.text)
# 通过对象调用实例方法
d.instance_method()
# 通过对象调用类方法
d.class_method()
# 通过对象调用静态方法
d.static_method()
# 类可以访问类方法,静态方法
# 通过类访问text属性
print(Demo.text)
# 通过类调用类方法
Demo.class_method()
# 通过类调用静态方法
Demo.static_method()
区别
在定义静态方法和类方法时,@staticmethod
装饰的静态方法里面,想要访问类属性或调用实例方法,必须要把类名写上;
而@classmethod
装饰的类方法里面,会传一个cls
参数,代表本类,这样能够避免手写类名的硬编码.
在调用静态方法和类方法时,实际的写法都差不多,一般都是通过类名.静态方法()或者类名.类方法()
也可以用实例化对象去调用静态方法和类方法,但为了和实例方法区分,最好还是用类去调用静态方法和类方法.
使用场景
在定义类的时候,
假如不需要用到与类相关的属性或方法时,就用静态方法@staticmethod
;
假如需要用到与类相关的属性或者方法,然后又想表明这个方法是整个类通用的,而不是对象特异的,就可以使用类方法@classmethod