• 技术文章 >头条

    三分钟搞定Python中的装饰器

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

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

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

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

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    def addworld(func):

        def addfun():

            return func() + 'world'

        return addfun()

     

    @addworld

    def printhello():

        return 'hello'

     

    print(printhello)

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    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。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    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

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    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)

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    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方法就是一个只读属性。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    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学习网