• python中的装饰器


    装饰器是基于闭包的

    什么是装饰器
    装饰器是一个函数,主要作用是用来包装另一个函数或类
    包装的目的是在不改变原函数名(或类名) 的情况下改变或添加被包装对象的行为

    函数装饰器
    是指装饰器是一个函数,传入的是一个函数,返回的也是一个函数

    def mydeco(fn):
        def fx():
            print("++++++++++++++++")
            print('----------------')
        return fx
    
    @mydeco
    def myfunc():
        '''此函数将作为被装饰函数'''
        print("myfunc被调用")
    
    
    # myfunc上的@mydeco 等同于在
    # 此处加上 myfunc=mydeco(myfunc)
    myfunc()

    一 基于函数的装饰器

      1.不带参数的装饰器

    def debug(func):
        def wrapper():
            print("[DEBUG]: enter {}()".format(func.__name__))
            return func()
        return wrapper
    
    @debug
    def say_hello():
        print("hello!")

      2.带参数的装饰器

    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)
    def logging(level):
        def wrapper(func):
            def inner_wrapper(*args, **kwargs):
                print "[{level}]: enter function {func}()".format(
                    level=level,
                    func=func.__name__)
                return func(*args, **kwargs)
            return inner_wrapper
        return wrapper
    
    @logging(level='INFO')
    def say(something):
        print "say {}!".format(something)
    
    # 如果没有使用@语法,等同于
    # say = logging(level='INFO')(say)
    
    @logging(level='DEBUG')
    def do(something):
        print "do {}...".format(something)
    
    if __name__ == '__main__':
        say('hello')
        do("my work")

    https://www.cnblogs.com/cicaday/p/python-decorator.html

    二 基于类的装饰器

      1.不带参数的装饰器

    装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()方法,那么这个对象就是callable的

    class Test():
        def __call__(self):
            print 'call me!'
    
    t = Test()
    t()  # call me

    __call__这样前后都带下划线的方法在Python中被称为内置方法,有时候也被称为魔法方法。重载这些魔法方法一般会改变对象的内部行为。上面这个例子就让一个类对象拥有了被调用的行为。

    回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文)。那么用类来实现也是也可以的。我们可以让类的构造函数__init__()接受一个函数,然后重载__call__()并返回一个函数,也可以达到装饰器函数的效果。

    class logging(object):
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            print "[DEBUG]: enter function {func}()".format(
                func=self.func.__name__)
            return self.func(*args, **kwargs)
    @logging
    def say(something):
        print "say {}!".format(something)

      2带参数的类装饰器

      如果需要通过类形式实现带参数的装饰器,那么会比前面的例子稍微复杂一点。那么在构造函数里接受的就不是一个函数,而是传入的参数。通过类把这些参数保存起来。然后在重载__call__方法是就需要接受一个函数并返回一个函数。

    class logging(object):
        def __init__(self, level='INFO'):
            self.level = level
            
        def __call__(self, func): # 接受函数
            def wrapper(*args, **kwargs):
                print "[{level}]: enter function {func}()".format(
                    level=self.level,
                    func=func.__name__)
                func(*args, **kwargs)
            return wrapper  #返回函数
    
    @logging(level='INFO')
    def say(something):
        print "say {}!".format(something)

      

      python自带的装饰器@property

    @property
    考察 Student 类:
    
    class Student(object):
        def __init__(self, name, score):
            self.name = name
            self.score = score
    当我们想要修改一个 Student 的 scroe 属性时,可以这么写:
    
    s = Student('Bob', 59)
    s.score = 60
    但是也可以这么写:
    
    s.score = 1000
    显然,直接给属性赋值无法检查分数的有效性。
    
    如果利用两个方法:
    
    class Student(object):
        def __init__(self, name, score):
            self.name = name
            self.__score = score
        def get_score(self):
            return self.__score
        def set_score(self, score):
            if score < 0 or score > 100:
                raise ValueError('invalid score')
            self.__score = score
    这样一来,s.set_score(1000) 就会报错。
    
    这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。
    
    但是写 s.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。
    
    有没有两全其美的方法?----有。
    
    因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:
    
    class Student(object):
        def __init__(self, name, score):
            self.name = name
            self.__score = score
        @property
        def score(self):
            return self.__score
        @score.setter
        def score(self, score):
            if score < 0 or score > 100:
                raise ValueError('invalid score')
            self.__score = score
    注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。
    
    现在,就可以像使用属性一样设置score了:
    
    >>> s = Student('Bob', 59)
    >>> s.score = 60
    >>> print s.score
    60
    >>> s.score = 1000
    Traceback (most recent call last):
      ...
    ValueError: invalid score
    说明对 score 赋值实际调用的是 set方法。
    
    任务
    如果没有定义set方法,就不能对“属性”赋值,这时,就可以创建一个只读“属性”。
    
    请给Student类加一个grade属性,根据 score 计算 A(>=80)、B、C(<60)。
    复制代码
    复制代码
    class Student(object):
    
        def __init__(self, name, score):
            self.name = name
            self.__score = score
    
        @property
        def score(self):
            return self.__score
    
        @score.setter
        def score(self, score):
            if score < 0 or score > 100:
                raise ValueError('invalid score')
            self.__score = score
    
        ???
    
    s = Student('Bob', 59)
    print s.grade
    
    s.score = 60
    print s.grade
    
    s.score = 99
    print s.grade
    
    
    
  • 相关阅读:
    创建一个 mac 的后台进程(daemon)
    Centos 7创建一个服务
    MAC配置VIM环境
    Spark源码剖析(九):TaskScheduler原理与源码剖析
    Spark源码剖析(八):stage划分原理与源码剖析
    教你如何写递归(数学归纳法,干货强推!)
    Spark源码剖析(七):Job触发流程原理与源码剖析
    剑指offer:变态跳台阶
    Spark源码剖析(六):Worker原理与源码剖析
    Spark源码剖析(五):Master原理与源码剖析(下)
  • 原文地址:https://www.cnblogs.com/taysem/p/10822118.html
Copyright © 2020-2023  润新知