Python学习之深入,装饰器学习以及实际使用场景实践
分类:微服架构

Python 装饰器学习以及实际使用场景实践

前言

前几天在看Flask框架,,不是非常的理解,回来补装饰器的功课。阅读很多的关于装饰器的文章,自己整理一下,适合自己的思路的方法和例子,与大家分享。

图片 1

app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" 

1、装饰器是什么

装饰器是Python语言中的高级语法。主要的功能是对一个函数、方法、或者类进行加工,作用是为已经存在的对象添加额外的功能,提升代码的可读性。
装饰器是设计模式的一种,被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等

2、装饰器的语法

装饰器的语法如下:

当前Python的装饰器语法如下:

@dec2 @dec1 def func(arg1, arg2, ...):     ....     return funx  上面的代码相当于:  def func(arg1, arg2, ...):     pass func = dec2(dec1(func)) 

装饰器可以用def的形式来定义。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。
装饰器新建了一个可调用对象,也就是return 返回的函数funx,在新增的函数中,可以添加我们需要的功能,并通过调用原有函数来实现原有函数的功能。

3、装饰器的使用

3.1不带参数的装饰器

定义装饰器非常的简单:

def deco(func):     """无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法"""     print "before myfunc() called."     func()     print "after myfunc() called."     return func  @deco def myfunc():     print " myfunc) called."   myfunc() myfunc() 

定义好装饰器后,,,即可使用。上面这个装饰器在使用的时候有一个问题,即只在第一次被调用,并且原来的函数多执行一次。执行输出如下:

before myfunc() called.   myfunc() called. after myfunc() called.  myfunc() called.   --函数多执行一次的输出  myfunc() called.   --第二次调用,装饰器不生效 

要保证新函数每次被调用,使用下面的方法来定义装饰器

def deco(func):     """无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法"""     def _deco():         print "before myfunc() called."         func()         print "after myfunc() called."         #return func 不需要返回func     retrun _deco @deco def myfunc():     print " myfunc) called."     return 'OK' myfunc() myfunc() 

函数输出如下:

before myfunc() called.  myfunc() called.   after myfunc() called. before myfunc() called.  myfunc() called.   after myfunc() called. 

这样可以看到,装饰器每次都得到了调用。

3.2带参数的函数进行装饰器

def deco(func):     def _deco(a, b):         print("before myfunc() called.")         ret = func(a, b)         print("  after myfunc() called. result: %s" % ret)     return ret return _deco  @deco def myfunc(a, b):     print(" myfunc(%s,%s) called." % (a, b))     return a + b   myfunc(1, 2) myfunc(3, 4) 

输出:

before myfunc() called. myfunc() called. After myfunc() called. result: 3 before myfunc() called. myfunc() called. After myfunc() called. result: 7 

内嵌函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数。

3.3装饰器带参数

def decoWithArgs(arg): """由于有参数的decorator函数在调用时只会使用应用时的参数而不接收被装饰的函数做为参数,    所以必须返回一个decorator函数, 由它对被装饰的函数进行封装处理""" def newDeco(func):    #定义一个新的decorator函数     def replaceFunc():    #在decorator函数里面再定义一个内嵌函数,由它封装具体的操作         print "Enter decorator %s" %arg    #进行额外操作         return func()    #对被装饰函数进行调用     return replaceFunc return newDeco    #返回一个新的decorator函数  @decoWithArgs("demo") def MyFunc():    #应用@decoWithArgs修饰的方法     print "Enter MyFunc"  MyFunc()    #调用被装饰的函数 

输出:
nter decorator demo
Enter MyFunc

这个情形适用于原来的函数没有参数,新增加打印的情况。常见适用的地方是增加函数的打印日志。

3.4对参数数量不确定的函数进行装饰

下面的例子是一个邮件异步发送的例子,函数的参数数据部确定,装饰器实现了对于邮件发送函数的异步发送。

from threading import Thread  def async(f):     def wrapper(*args, **kwargs):         thr = Thread(target = f, args = args, kwargs = kwargs)         thr.start()     return wrapper  @async def send_async_email(msg):     mail.send(msg)  def send_email(subject, sender, recipients, text_body, html_body):     msg = Message(subject, sender = sender, recipients = recipients)     msg.body = text_body     msg.html = html_body     send_async_email(msg) 

并且这个装饰器可以适用一切需要异步处理的功能,做到非常好的代码复用。

3.5让装饰器带类参数

class locker:     def __init__(self):         print("locker.__init__() should be not called.")               @staticmethod     def acquire():         print("locker.acquire() called.这是静态方法)")               @staticmethod     def release():         print("  locker.release() called.不需要对象实例)")   def deco(cls):     '''cls 必须实现acquire和release静态方法'''     def _deco(func):         def __deco():             print("before %s called [%s]." % (func.__name__, cls))             cls.acquire()             try:                 return func()             finally:                 cls.release()         return __deco     return _deco   @deco(locker) def myfunc():     print(" myfunc() called.")   myfunc() myfunc() 

输出为:

before myfunc called [__main__.locker]. locker.acquire() called.(this is staticmethon) myfunc() called.   locker.release() called.(do't need object )  before myfunc called [__main__.locker]. locker.acquire() called.(this is staticmethon) myfunc() called.   locker.release() called.(do't need object ) 

装饰器总结

当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现。

参考文章

感谢以下几位大神:


图片 2


装饰器学习以及实际使用场景实践 前言 前几天在看Flask框架,,不是非常的理解,回来补装饰器的功课。阅读很多的关于装饰器的文...

装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。

姓名:何承勇

装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(callable object,这样的对象定义有__call__方法)。在Python 2.6以及之后的Python版本中,装饰器被进一步用于加工类。

学号:16050510005

装饰函数和方法

我们先定义两个简单的数学函数,一个用来计算平方和,一个用来计算平方差:

图片 3

# get square sumdef square_sum:    return a**2 + b**2# get square diffdef square_diff:    return a**2 - b**2

print(square_sum(3, 4))print(square_diff

图片 4

在拥有了基本的数学功能之后,我们可能想为函数增加其它的功能,比如打印输入。我们可以改写函数来实现这一点:

图片 5

# modify: print input# get square sumdef square_sum:    print("intput:", a, b)    return a**2 + b**2# get square diffdef square_diff:    print("input", a, b)    return a**2 - b**2

print(square_sum(3, 4))print(square_diff

图片 6

我们修改了函数的定义,为函数增加了功能。

现在,我们使用装饰器来实现上述修改:

图片 7

def decorator:    def new_F:        print("input", a, b)        return F    return new_F# get square sum@decoratordef square_sum:    return a**2 + b**2# get square diff@decoratordef square_diff:    return a**2 - b**2print(square_sum(3, 4))print(square_diff

图片 8

装饰器可以用def的形式定义,如上面代码中的decorator。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。装饰器新建了一个可调用对象,也就是上面的new_F。new_F中,我们增加了打印的功能,并通过调用F来实现原有函数的功能。

定义好装饰器后,我们就可以通过@语法使用了。在函数square_sum和square_diff定义之前调用@decorator,我们实际上将square_sum或square_diff传递给decorator,并将decorator返回的新的可调用对象赋给原来的函数名(square_sum或square_diff)。 所以,当我们调用square_sum的时候,就相当于:

square_sum = decorator(square_sum)square_sum(3, 4)

我们知道,Python中的变量名和对象是分离的。变量名可以指向任意一个对象。从本质上,装饰器起到的就是这样一个重新指向变量名的作用(name binding),让同一个变量名指向一个新返回的可调用对象,从而达到修改可调用对象的目的。

与加工函数类似,我们可以使用装饰器加工类的方法。

如果我们有其他的类似函数,我们可以继续调用decorator来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

转载自:

含参的装饰器

在上面的装饰器调用中,比如@decorator,该装饰器默认它后面的函数是唯一的参数。装饰器的语法允许我们调用decorator时,提供其它参数,比如@decorator。这样,就为装饰器的编写和使用提供了更大的灵活性。

图片 9

# a new wrapper layerdef pre_str(pre=''):    # old decorator    def decorator:        def new_F:            print(pre + "input", a, b)            return F        return new_F    return decorator# get square sum@pre_str('^_^')def square_sum:    return a**2 + b**2# get square diff@pre_str('T_T')def square_diff:    return a**2 - b**2print(square_sum(3, 4))print(square_diff

图片 10

上面的pre_str是允许参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有环境参量的闭包。当我们使用@pre_str调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。该调用相当于:

square_sum = pre_str('^_^') (square_sum)

【嵌牛导读】:Python一切皆对象,但同时,Python还是一个多范式语言(multi-paradigm),你不仅可以使用面向对象的方式来编写程序,还可以用面向过程的方式来编写相同功能的程序(还有函数式、声明式等,我们暂不深入)。

装饰类

在上面的例子中,装饰器接收一个函数,并返回一个函数,从而起到加工函数的效果。在Python 2.6以后,装饰器被拓展到类。一个装饰器可以接收一个类,并返回一个类,从而起到加工类的效果。

图片 11

def decorator:    class newClass:        def __init__(self, age):            self.total_display   = 0            self.wrapped         = aClass        def display:            self.total_display += 1            print("total display", self.total_display)            self.wrapped.display()    return newClass@decoratorclass Bird:    def __init__(self, age):        self.age = age    def display:        print("My age is",self.age)eagleLord = Bird(5)for i in range(3):    eagleLord.display()

图片 12

在decorator中,我们返回了一个新类newClass。在新类中,我们记录了原来类生成的对象(self.wrapped),并附加了新的属性total_display,用于记录调用display的次数。我们也同时更改了display方法。

通过修改,我们的Bird类可以显示调用display的次数了。

本文主要讲述Python的闭包和装饰器等内容。

总结

装饰器的核心作用是name binding。这种语法是Python多编程范式的又一个体现。大部分Python用户都不怎么需要定义装饰器,但有可能会使用装饰器。鉴于装饰器在Python项目中的广泛使用,了解这一语法是非常有益的。

【嵌牛鼻子】:Python、高级语法

【嵌牛提问】:Python高级语法里的装饰器是什么?闭包又与我们离散数学中学得的概念有何差异?

【嵌牛正文】:

闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。

函数对象的作用域

和其他对象一样,函数对象也有其存活的范围,也就是函数对象的作用域。函数对象是使用def语句定义的,函数对象的作用域与def所在的层级相同。比如下面代码,我们在line_conf函数的隶属范围内定义的函数line,就只能在line_conf的隶属范围内调用。

图片 13

line函数定义了一条直线(y = 2x + 1)。可以看到,在line_conf()中可以调用line函数,而在作用域之外调用line将会有下面的错误:

图片 14

说明这时已经在作用域之外。

同样,如果使用lambda定义函数,那么函数对象的作用域与lambda所在的层级相同。

闭包

函数是一个对象,所以可以作为某个函数的返回结果

图片 15

上面的代码可以成功运行。line_conf的返回结果被赋给line对象。上面的代码将打印11。

如果line()的定义中引用了外部的变量,会发生什么呢?

图片 16

我们可以看到,line定义的隶属程序块中引用了高层级的变量b,但b信息存在于line的定义之外 (b的定义并不在line的隶属程序块中)。我们称b为line的环境变量。事实上,line作为line_conf的返回值时,line中已经包括b的取值(尽管b并不隶属于line)。

上面的代码将打印25,也就是说,line所参照的b值是函数对象定义时可供参考的b值,而不是使用时的b值。

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的__closure__属性中。比如下面的代码:

图片 17

__closure__里包含了一个元组(tuple)。这个元组中的每个元素是cell类型的对象。我们看到第一个cell包含的就是整数15,也就是我们创建闭包时的环境变量b的取值。

下面看一个闭包的实际例子:

图片 18

这个例子中,函数line与环境变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。利用闭包,我们实际上创建了泛函。line函数定义一种广泛意义的函数。这个函数的一些方面已经确定(必须是直线),但另一些方面(比如a和b参数待定)。随后,我们根据line_conf传递来的参数,通过闭包的形式,将最终函数确定下来。

闭包与并行运算

闭包有效的减少了函数所需定义的参数数目。这对于并行运算来说有重要的意义。在并行运算的环境下,我们可以让每台电脑负责一个函数,然后将一台电脑的输出和下一台电脑的输入串联起来。最终,我们像流水线一样工作,从串联的电脑集群一端输入数据,从另一端输出数据。这样的情境最适合只有一个参数输入的函数。闭包就可以实现这一目的。

并行运算正称为一个热点。这也是函数式编程又热起来的一个重要原因。函数式编程早在1950年代就已经存在,但应用并不广泛。然而,我们上面描述的流水线式的工作并行集群过程,正适合函数式编程。由于函数式编程这一天然优势,越来越多的语言也开始加入对函数式编程范式的支持。

装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。

装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(callable object,这样的对象定义有__call__方法)。在Python 2.6以及之后的Python版本中,装饰器被进一步用于加工类。

装饰函数和方法

我们先定义两个简单的数学函数,一个用来计算平方和,一个用来计算平方差:

图片 19

在拥有了基本的数学功能之后,我们可能想为函数增加其它的功能,比如打印输入。我们可以改写函数来实现这一点:

图片 20

我们修改了函数的定义,为函数增加了功能。

现在,我们使用装饰器来实现上述修改:

图片 21

装饰器可以用def的形式定义,如上面代码中的decorator。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。装饰器新建了一个可调用对象,也就是上面的new_F。new_F中,我们增加了打印的功能,并通过调用F(a, b)来实现原有函数的功能。

定义好装饰器后,我们就可以通过@语法使用了。在函数square_sum和square_diff定义之前调用@decorator,我们实际上将square_sum或square_diff传递给decorator,并将decorator返回的新的可调用对象赋给原来的函数名(square_sum或square_diff)。 所以,当我们调用square_sum(3, 4)的时候,就相当于:

图片 22

我们知道,Python中的变量名和对象是分离的。变量名可以指向任意一个对象。从本质上,装饰器起到的就是这样一个重新指向变量名的作用(name binding),让同一个变量名指向一个新返回的可调用对象,从而达到修改可调用对象的目的。

与加工函数类似,我们可以使用装饰器加工类的方法。

如果我们有其他的类似函数,我们可以继续调用decorator来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

含参的装饰器

在上面的装饰器调用中,比如@decorator,该装饰器默认它后面的函数是唯一的参数。装饰器的语法允许我们调用decorator时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。

图片 23

上面的pre_str是允许参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有环境参量的闭包。当我们使用@pre_str('^_^')调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。该调用相当于:

图片 24

装饰类

在上面的例子中,装饰器接收一个函数,并返回一个函数,从而起到加工函数的效果。在Python 2.6以后,装饰器被拓展到类。一个装饰器可以接收一个类,并返回一个类,从而起到加工类的效果。

图片 25

在decorator中,我们返回了一个新类newClass。在新类中,我们记录了原来类生成的对象(self.wrapped),并附加了新的属性total_display,用于记录调用display的次数。我们也同时更改了display方法。

通过修改,我们的Bird类可以显示调用display的次数了。

总结:

装饰器的核心作用是name binding。这种语法是Python多编程范式的又一个体现。大部分Python用户都不怎么需要定义装饰器,但有可能会使用装饰器。鉴于装饰器在Python项目中的广泛使用,了解这一语法是非常有益的。

原文作者:Vamei

本文由10bet手机官网发布于微服架构,转载请注明出处:Python学习之深入,装饰器学习以及实际使用场景实践

上一篇:动态调整磁盘容量,CentOS下删除一个卷组10bet体育中文官网 下一篇:python表格存取的方法,Python实现的简单读写csv文件操作示例
猜你喜欢
热门排行
精彩图文