zoukankan      html  css  js  c++  java
  • Python-装饰器进阶

    基本概念

    具体概念请先看之前的文章 理解装饰器

    装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理, Web权限校验, Cache等。

    很有名的例子,就是咖啡,加糖的咖啡,加牛奶的咖啡。本质上,还是咖啡,只是在原有的东西上,做了“装饰”,使之附加一些功能或特性。

    例如记录日志,需要对某些函数进行记录

    笨的办法,每个函数加入代码,如果代码变了,就悲催了

    装饰器的办法,定义一个专门日志记录的装饰器,对需要的函数进行装饰,搞定

    优点

    抽离出大量函数中与函数功能本身无关的雷同代码并继续重用

    即,可以将函数“修饰”为完全不同的行为,可以有效的将业务逻辑正交分解,如用于将权限和身份验证从业务中独立出来

    概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能

    Python中的装饰器

    在Python中,装饰器实现是十分方便的

    原因是:函数可以被扔来扔去。

    函数作为一个对象:

    A.可以被赋值给其他变量,可以作为返回值
    
    B.可以被定义在另外一个函数内
    

    def:

    装饰器是一个函数,一个用来包装函数的函数,装饰器在函数申明完成的时候被调用,调用之后返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问(申明的函数被换成一个被装饰器装饰过后的函数)

    当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。

    由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现

    分类:

    装饰器分为无参数decorator,有参数decorator

    * 无参数decorator
    
    生成一个新的装饰器函数
    
    * 有参decorator
    
    有参装饰,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰
    

    装饰器有参/无参,函数有参/无参,组合共4种

    具体定义:

    decorator方法

    A.把要装饰的方法作为输入参数,

    B.在函数体内可以进行任意的操作(可以想象其中蕴含的威力强大,会有很多应用场景),

    C.只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数, 或者是一个新函数)

    无参数装饰器 – 包装无参数函数

    不需要针对参数进行处理和优化

    def decorator(func):
        print "hello"
        return func
    
    @decorator
    def foo():
        pass
    
    foo()

    foo()等价于:

    foo = decorator(foo)
    foo()

    无参数装饰器 – 包装带参数函数

    def decorator_func_args(func):
        def handle_args(*args, **kwargs): #处理传入函数的参数
            print "begin"
            func(*args, **kwargs)   #函数调用
            print "end"
        return handle_args
    
    
    @decorator_func_args
    def foo2(a, b=2):
        print a, b
    
    foo2(1)

    foo2(1)等价于

    foo2 = decorator_func_args(foo2)
    foo2(1)

    带参数装饰器 – 包装无参数函数

    def decorator_with_params(arg_of_decorator):#这里是装饰器的参数
        print arg_of_decorator
        #最终被返回的函数
        def newDecorator(func): 
            print func
            return func
        return newDecorator
    
    
    @decorator_with_params("deco_args") #注意装饰器参数是这时候使用的
    def foo3():
        pass
    foo3()

    与前面的不同在于:比上一层多了一层封装,先传递参数,再传递函数名

    第一个函数decomaker是装饰函数,它的参数是用来加强“加强装饰”的。由于此函数并非被装饰的函数对象,所以在内部必须至少创建一个接受被 装饰函数的函数,然后返回这个对象(实际上此时foo3= decorator_with_params(arg_of_decorator)(foo3))

    带参数装饰器– 包装带参数函数

    def decorator_whith_params_and_func_args(arg_of_decorator):
        def handle_func(func):
            def handle_args(*args, **kwargs):
                print "begin"
                func(*args, **kwargs)
                print "end"
                print arg_of_decorator, func, args,kwargs
            return handle_args
        return handle_func
    
    
    @decorator_whith_params_and_func_args("123")
    def foo4(a, b=2):
        print "Content"
    
    foo4(1, b=3)

      实际上此时foo3= decorator_with_params(arg_of_decorator)(foo4)

    内置装饰器

    内置的装饰器有三个:staticmethod,classmethod, property

    class A():
        @staticmethod
        def test_static():
            print "static"
        def test_normal(self):
            print "normal"
        @classmethod
        def test_class(cls):
            print "class", cls
    
    a = A()
    A.test_static()
    a.test_static()
    a.test_normal()
    a.test_class()

    结果:

    static
    static
    normal
    class __main__.A

    A.test_static

    staticmethod 类中定义的实例方法变成静态方法

    基本上和一个全局函数差不多(不需要传入self,只有一般的参数),只不过可以通过类或类的实例对象来调用,不会隐式地传入任何参数。

    类似于静态语言中的静态方法

    B.test_normal

    普通对象方法:普通对象方法至少需要一个self参数,代表类对象实例

    C.test_class

    类中定义的实例方法变成类方法

    classmethod需要传入类对象,可以通过实例和类对象进行调用。

    是和一个class相关的方法,可以通过类或类实例调用,并将该class对象(不是class的实例对象)隐式地当作第一个参数传入。

    就这种方法可能会 比较奇怪一点,不过只要你搞清楚了python里class也是个真实地存在于内存中的对象,而不是静态语言中只存在于编译期间的类型,就好办了。正常的 方法就是和一个类的实例对象相关的方法,通过类实例对象进行调用,并将该实例对象隐式地作为第一个参数传入,这个也和其它语言比较像。

    D.区别

    staticmethod,classmethod相当于全局方法,一般用在抽象类或父类中。一般与具体的类无关。

    类方法需要额外的类变量cls,当有子类继承时,调用类方法传入的类变量cls是子类,而不是父类。

    类方法和静态方法都可以通过类对象和类的实例对象访问

    定义方式,传入的参数,调用方式都不相同。

    E.property

    对类属性的操作,类似于java中定义getter/setter

    class B():
        def __init__(self):
            self.__prop = 1
        @property
        def prop(self):
            print "call get"
            return self.__prop
        @prop.setter
        def prop(self, value):
            print "call set"
            self.__prop = value
        @prop.deleter
        def prop(self):
            print "call del"
            del self.__prop

    其他

    A.装饰器的顺序很重要,需要注意

    @A
    @B
    @C
    def f ():
    ...

    等价于

    f = A(B(C(f)))

    B.decorator的作用对象可以是模块级的方法或者类方法

    C.functools模块提供了两个装饰器。这个模块是Python 2.5后新增的。

    functools.wraps(func)total_ordering(cls)这个具体自己去看吧,后续用到了再补充

    一个简单例子

    通过一个变量,控制调用函数时是否统计时间

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    #@author: wklken@yeah.net
    #@version: a test of decorator
    #@date: 20121027
    #@desc: just a test
    
    
    import logging
    
    from time import time
    
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    is_debug = True
    
    def count_time(is_debug):
        def  handle_func(func):
            def  handle_args(*args, **kwargs):
                if is_debug:
                    begin = time()
                    func(*args, **kwargs)
                    logging.debug( "[" + func.__name__ + "] -> " + str(time() - begin) )
                else:
                    func(*args, **kwargs)
            return handle_args
        return handle_func
    
    def pr():
        for i in range(1,1000000):
            i = i * 2
        print "hello world"
    
    def test():
        pr()
    
    @count_time(is_debug)
    def test2():
        pr()
    
    @count_time(False)
    def test3():
        pr()
    
    if __name__ == "__main__":
        test()
        test2()
        test3()

    结果:

    hello world
    hello world
    DEBUG:root:[test2] -> 0.0748538970947
    hello world

    转自:http://blog.csdn.net/wklken/article/details/8118942

    参考:http://blog.csdn.net/dreamcoding/article/details/8611578

  • 相关阅读:
    hdu2328 Corporate Identity
    hdu1238 Substrings
    hdu4300 Clairewd’s message
    hdu3336 Count the string
    hdu2597 Simpsons’ Hidden Talents
    poj3080 Blue Jeans
    poj2752 Seek the Name, Seek the Fame
    poj2406 Power Strings
    hust1010 The Minimum Length
    hdu1358 Period
  • 原文地址:https://www.cnblogs.com/JohnABC/p/4186209.html
Copyright © 2011-2022 走看看