• 技术文章 >头条

    三分钟搞定Python中的装饰器

    silencementsilencement2019-07-12 16:58:51原创3992

    python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能。

    装饰器存在的意义是什么呢?我们知道,在python中函数可以调用,类可以继承,为何要必须保证不改变函数和类的定义,就使得函数有了新的功能呢?其实很好解释。

    提高代码的简洁程度与封装性。如果你采用新声明一个函数,并调用原来函数的思路使得原函数功能增加了,但是一方面使用起来看着不简洁, 另一方面当另一个程序员使用你的代码时再使用这样的思路,那代码嵌套无穷无尽,会让代码变得很乱,说不定改错了哪里,动了原函数哪个参数,就会出现发现不了的bug。

    我们先来看一个简单的例子。

    def addworld(func):
        def addfun():
            return func() + 'world'
        return addfun()
    
    @addworld
    def printhello():
        return 'hello'
    
    print(printhello)

    这段代码最后运行出来的结果是helloworld。我们发现,只要在原函数头上加一个你定义好了的增添功能的模板,以后凡是加上这个,都会增添一个功能,这提高了开发效率,也看着更加简洁。

    def addnum(func):
        def addfun(*args, **kwargs):
            ret = func(*args, **kwargs)*2
            return ret
        return addfun
    
    @addnum
    def printsum(a, b):
        return (a+b)
    
    i = printsum(7, 7)
    print(i)

    这是有参数的情况下,装饰器的使用效果,输出结果为28。

    def addnum1(c):
        def addnum(func):
            def addfun(*args, **kwargs):
                ret = func(*args, **kwargs)*2*c
                return ret
            return addfun
        return addnum
    
    @addnum1(5)
    def printsum(a, b):
        return (a+b)
    
    i = printsum(7, 7)
    print(i)

    装饰器本身也是可以传参的,在这个程序中,传入了一个常数5,最后得出的结果是140。

    接下来,我们介绍几个常用的python内置装饰器。

    property

    在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改。这样显然是不行的,那么在函数中,我们往往如何提高程序的鲁棒性呢?

    class Student(object):
    
        def get_score(self):
            return self._score
    
        def set_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.set_score(60)
    value = s.get_score()
    print(value)

    通过调用类中的函数从而进一步操作属性,这样虽然安全正确却未免看着复杂,不贴近人类自然的属性表现。

    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 = 80
    print(s.score)

    而加上一个@property就可以轻松解决这个问题,是不是很奇妙?把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作。

    还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性。

    class Student(object):
    
        @property
        def birth(self):
            return self._birth
    
        @birth.setter
        def birth(self, value):
            self._birth = value
    
        @property
        def age(self):
            return 2014 - self._birth

    上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。

    专题推荐:装饰器
    上一篇:超级简单的requests模块教程 下一篇:新手必学的使用命令行实现tab键自动补全功能

    相关文章推荐

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网