装饰器
特点
:装饰器其实也就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问,在特定的业务领域里,能减少大量重复代码。
它的参数就是被装饰的函数对象。我们可以在deco函数内对传入的函数对象做一番“装饰”,然后返回这个对象(
记住一定要返回
(返回func的时候,就是调用这个函数),不然外面调用foo的地方将会无函数可用。
基本用法(无参):
def foo(func):
print 'decorator foo'
return func
@foo
def bar():
print 'bar'
bar()
# 输出结果
# decorator foo
# bar
详解:
foo 函数被用作装饰器,其本身接收一个函数对象作为参数,然后做一些工作后,返回接收的参数,供外界调用。
注意:
时刻牢记
@foo
只是一个语法糖,其本质是
foo = bar(foo)
计算性能时间(装饰器有参):
import time
def function_performance_statistics(trace_this=True):
if trace_this:
def performace_statistics_delegate(func):
def counter(*args, **kwargs):
start = time.clock()
func(*args, **kwargs)
end = time.clock()
print 'used time: %d' % (end - start,)
return counter
else:
def performace_statistics_delegate(func):
return func
return performace_statistics_delegate
@function_performance_statistics(True)
def add(x, y):
time.sleep(3)
print 'add result: %d' % (x + y,)
@function_performance_statistics(False)
def mul(x, y=1):
print 'mul result: %d' % (x * y,)
add(1, 1)
mul(10)
# 输出结果
# add result: 2
# used time: 2
# mul result: 10
装饰器中使用函数参数:
def deco(func):
def _deco(c, d):
print("before myfunc(%s, %s) called." % (c, d))
ret = func(c, d)
print(" after myfunc(%s, %s) called. result: %s" % (c, d, ret))
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a + b
myfunc(1, 2)
# 输出内容
# before myfunc(1, 2) called.
# myfunc(1,2) called.
# after myfunc(1, 2) called. result: 3
类装饰器:
class Foo(object):
def __init__(self, func):
super(Foo, self).__init__()
self._func = func
def __call__(self):
print 'class decorator'
self._func()
@Foo
def bar():
print 'bar'
bar()
# 输出结果
# class decorator
# bar
详解:
类装饰器相比函数装饰器,具有灵活度大,高内聚、封装性等优点。其实现起来主要是靠类内部的
__call__
方法,当使用
@
形式将装饰器附加到函数上时,就会调用__call__方法
Python内置常用三个装饰器:
@staticmethod:
类静态方法,其跟成员方法的区别是没有
self
指针,并且可以在类不进行实例化的情况下调用,下面是一个实例,对比静态方法和成员方法
class Foo(object):
@staticmethod
def static_method(msg):
print msg
def member_method(self, msg):
print msg
foo = Foo()
foo.member_method('some msg')
foo.static_method('static some msg')
Foo.static_method('class some msg')
# 输出结果
# some msg
# static some msg
详解:
可以通过实例访问,也可以通过类访问
@classmethod:
与成员方法的区别在于所接收的第一个参数不是
self
类实例的指针,而是当前类。
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
@classmethod
def get_no_of_instance(cls_obj):
return cls_obj.no_inst
ik1 = Kls()
ik2 = Kls()
print ik1.get_no_of_instance()
print Kls.get_no_of_instance()
# 输出结果
# 2
# 2
@property
广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
s = Student()
s.score = 90
print s.score
s.score = 150
print s.score
# 输出结果
# 90
# ValueError: score must between 0 ~ 100!
详解:
在访问Student的实例s中的score时,无论是访问还是修改可以直接调用s.score去操作,像标准的写法应该是写set和get函数,@property修饰器帮我们搞掂了。这样调用者更加简单
注意:
这个类没有在__init__()中注明了score成员元素,所以只有先s.score = 90的时候,score属性才会存在。节省了内存