资讯专栏INFORMATION COLUMN

Python Decorator的设计模式演绎过程解析

89542767 / 213人阅读

  小编写这篇文章的一个主要目的,主要是给大家去做一个相关的解答,解答的内容主要是涉及到python一些相关事宜,主要是给大家详解的是Python Decorator的一些相关事宜,比如讲一下他们的底层原理,关于设计模式演绎过程,下面就给大家详细解答下。


  关于代理模式、装饰模式


  设计模式中经常提到的代理模式、装饰模式,这两种叫法实际上是说的同一件事,只是侧重点有所不同而已。


  这两者都是通过在原有对象的基础上封装一层对象,通过调用封装后的对象而不是原来的对象来实现代理/装饰的目的。


  例如:(以Java为例)


  public class CountProxy implements Count{
  private CountImpl countImpl;
  public CountProxy(CountImpl countImpl){
  this.countImpl=countImpl;
  }
  Override
  public void queryCount(){
  System.out.println("事务处理之前");
  //调用委托类的方法;
  countImpl.queryCount();
  System.out.println("事务处理之后");
  }
  Override
  public void updateCount(){
  System.out.println("事务处理之前");
  //调用委托类的方法;
  countImpl.updateCount();
  System.out.println("事务处理之后");
  }
  }


  在这个例子中CountProxy是对CountImpl的封装。


  使用者通过CountProxy.queryCount方法来调用CountImpl.queryCount方法,这被称为代理,即CountProxy是代理类,CountImpl是被代理类。


  在CountProxy.queryCount方法中,可以在CountImpl.queryCount方法调用之前和之后添加一些额外的操作,被称为装饰,即CountProxy是装饰类,CountImpl是被装饰类。


  如果强调通过CountProxy对CountImpl进行代理的作用,则称为代理模式;


  如果强调通过CountProxy对CountImpl增加额外的操作,则称为装饰模式;


  不论是哪种称呼,其本质都在于对原有对象的封装。


  其封装的目的在于增强所封装对象的功能或管理所封装的对象。


  从上面的例子也可以发现,代理/封装所围绕的核心是可调用对象(比如函数)。


  Python中的代理/装饰


  Python中的可调用对象包括函数、方法、实现了__call__方法的类。


  Python中的函数也是对象,可以作为高阶函数的参数传入或返回值返回。


  因此,当代理/装饰的对象是函数时,可以使用高阶函数来对某个函数进行封装。


  例如:


  def query_count_proxy(fun,name,age):
  print('do something before')
  rv=fun(name,age)
  print('do something after')
  return rv
  def query_count(name,age):
  print('name is%s,age is%d'%(name,age))
  query_count_proxy(query_count,'Lee',20)


  但是,这个例子中,query_count函数作为参数传入query_count_proxy函数中,并在query_count_proxy函数中被调用,其结果作为返回值返回。这就完成了代理的功能,同时,在调用query_count函数的前后,我们还增加了装饰代码。


  但是,query_count_proxy的函数参数与query_count不一样了,理想的代理应该保持接口一致才对。


  为了保持一致,我们可以利用高阶函数可以返回函数的特点来完成:


  def query_count_proxy(fun):
  def wrapper(name,age):
  print('do something before')
  rv=fun(name,age)
  print('do something after')
  return rv
  return wrapper
  def query_count(name,age):
  print('name is%s,age is%d'%(name,age))
  query_count_proxy(query_count)('Lee',20)


  修改后的例子,query_count_proxy仅负责接受被代理的函数query_count作为参数,同时,返回一个函数对象wrapper作为返回值,真正的封装动作在wrapper这个函数中完成。


  此时,如果调用query_count_proxy(query_count)就得到了wrapper函数对象,则,执行query_count_proxy(query_count)('Lee',20)就相当于执行了wrapper('Lee',20)。


  但是可以看到,query_count_proxy(query_count)('Lee',20)这种使用方法,仍然不能保证一致。


  为了保持一致,我们需要利用Python中对象与其名称可以动态绑定的特点。不使用query_count_proxy(quer_count)('Lee',20)来调用代理函数,而是使用下面两句:


  1


  2


  query_count=query_count_proxy(query_count)
  query_count('Lee',20)


  执行query_count_proxy(query_count)生成wrapper函数对象,将这个对象通过query_count=query_count_proxy(query_count)绑定到query_count这个名字上来,这样执行query_count('Lee',20)时,其实执行的是wrapper('Lee',20)。


  这么做的结果就是:使用代理时调用query_count('Lee',20)与不使用代理时调用query_count('Lee',20)对使用者而言保持不变,不用改变代码,但是在真正执行时,使用的是代理/装饰后的函数。


  这里,基本利用Python的高阶函数及名称绑定完成了代理/装饰的功能。


  还有什么不理想的地方呢?


  对,就是query_count=query_count_proxy(query_count),因为这句既不简洁,又属于重复工作。


  Python为我们提供了语法糖来完成这类的tedious work。


  方法就是:


  query_count_proxy
  def query_count(name,age):
  return'name is%s,age is%d'%(name,age)
  query_count=query_count_proxy(query_count)就等同于在定义query_count函数的时候,在其前面加上query_count_proxy。


  Python看到这样的语法,就会自动的执行query_count=query_count_proxy(query_count)进行name rebinding


  补充


  以上就是Python实现可调用对象装饰的核心。


  可调用对象包括函数、方法、实现了__call__方法的类,上述内容只是针对函数来解释,对于方法、实现了__call__方法的类,其基本原理相同,具体实现略有差别。


  以上就是小编为大家总结的,希望可以给各位读者带来帮助。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128314.html

相关文章

  • Python单例模式

    摘要:在中,我们可以用多种方法来实现单例模式使用模块使用使用装饰器使用元类使用模块其实,的模块就是天然的单例模式,因为模块在第一次导入时,会生成文件,当第二次导入时,就会直接加载文件,而不会再次执行模块代码。 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对...

    khlbat 评论0 收藏0
  • Python: 会打扮装饰器

    摘要:一般情况下,我们使用装饰器提供的语法糖,来简化上面的写法像上面的情况,可以动态修改函数或类功能的函数就是装饰器。本文标题为会打扮的装饰器本文链接为参考资料修饰器的函数式编程中的装饰器介绍思诚之道装饰器入门与提高赖明星 装饰器 我们知道,在 Python 中,我们可以像使用变量一样使用函数: 函数可以被赋值给其他变量 函数可以被删除 可以在函数里面再定义函数 函数可以作为参数传递给另外...

    blastz 评论0 收藏0
  • Python函数修饰器---当方法前遇到@参数化修饰器方法时发生

    一、前提概念   Python中的函数是对象。也因此,函数可以被当做变量使用。 二、代码模型 以下代码片段来自于: http://www.sharejs.com/codes/python/8361 # -*- coding: utf-8 -*- from threading import Thread import time class TimeoutEx...

    huashiou 评论0 收藏0
  • Python装饰器vs装饰器模式

    摘要:希望引以为戒郑传装饰模式如果你了解,你肯定听过装饰器模式。在面向对象中,装饰模式指动态地给一个对象添加一些额外的职责。就增加一些功能来说,装饰模式比生成子类更为灵活。 漫谈 如果作为一个Python入门,不了解Python装饰器也没什么,但是如果作为一个中级Python开发人员,如果再不对python装饰器熟稔于心的话,那么可能并没有量变积累到质变。 我以前也看过很多讲python 装...

    stackvoid 评论0 收藏0
  • Python知识点:理解和使用装饰器 @decorator

    摘要:使用类装饰器,优点是灵活性大,高内聚,封装性。不过不用担心,有,本身也是一个装饰器,它的作用就是把原函数的元信息拷贝到装饰器函数中,使得装饰器函数也有和原函数一样的元信息。 showImg(https://segmentfault.com/img/bVbrFWb?w=742&h=484);Python的装饰器(decorator)是一个很棒的机制,也是熟练运用Python的必杀技之一。...

    cyqian 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<