python基础篇--装饰器

装饰器
特点 装饰器其实也就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问,在特定的业务领域里,能减少大量重复代码。

它的参数就是被装饰的函数对象。我们可以在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属性才会存在。节省了内存


你可能感兴趣的:(python基础篇)