设为首页 收藏本站
查看: 2507|回复: 0

[经验分享] python_类装饰器

[复制链接]

尚未签到

发表于 2018-8-5 14:00:59 | 显示全部楼层 |阅读模式
  一.定义
  装饰器就是一个给对象添加额外功能的函数,其本质是函数。它的基本构造:高阶函数+函数嵌套+闭包。基础知识讲解详见:http://blog.51cto.com/10836356/2095118
  二.简单类的装饰器
  我们先看简单的类的装饰器,如果我们需要给任意一个类添加一个打印功能,即:没当操作这个类时,就打印”定义了一个装饰类函数”,见下图:
DSC0000.jpg

  @Decorator          #相当于执行 School = Decorator(School)
  注释内容若有疑问,请参考:http://blog.51cto.com/10836356/2095118
  上面代码块为:
  

#给每个类打印一句话  
def Decorator(obj):
  print("定义了一个装饰器函数")
  return obj
  

  
@Decorator          #相当于执行 School = Decorator(School)
  
class School():
  pass
  

            如果我们要给该类添加一个数据属性和一个函数属性,又该如何定义这个装饰器呢?见下图:  

DSC0001.jpg

  代码块如下:
  

#给每个类添加一个数据属性和一个函数属性  
def Decorator(obj):# print(School.__dict__)
  #添加数据属性
  obj.addr = "浙江省杭州市"
  def price():
  pass
  #添加函数属性
  obj.price = price
  return obj
  

  
@Decorator          #相当于执行 School = Decorator(School)
  
class School():
  def __init__(self,name,price):
  self.name =name
  self.price =price
  

  
#打印类的属性字典
  
print(School.__dict__)
  

  三.高级类的装饰器
  此时,在实际场景中可能需要在装饰器中使用变量参数,那么该如何实现呢?
  在二中只利用了装饰器中的高阶函数的概念,要实现上述的需求,就需要使用装饰器构造的另外两部分:函数嵌套、闭包。如下图所示,我们需要给类添加一个数据属性,但是此时不同的类要求添加的属性是可变的,处理方法见下图:
DSC0002.jpg

  多个类使用该装饰器添加不同的属性,如下图:
DSC0003.jpg

  该部分代码块如下:
  

#给每个类添加一个可变的数据属性  
def Decorator(**kwargs):
  def add(obj):
  "添加数据属性"
  # print('调用外部函数的**kwargs',kwargs)
  for key,val in kwargs.items():
  # 添加数据属性
  setattr(obj,key,val)
  return obj
  # print("外部传入的参数为:",kwargs)
  return add
  

  
@Decorator(addr = "浙江省杭州市",name ="浙江大学")          #执行顺序:1.运行Decorator函数,先打印外部的传入的参数,返回add函数名;2.再执行School = add(School)
  
class School():
  def __init__(self,price):
  self.price =price
  

  
@Decorator(addr = "湖北省",price =12000)
  
class School1():
  pass
  

  
print(School.__dict__)
  
print(School1.__dict__)
  

  四.类的装饰器在实际中的应用
  我们在学习类时,介绍了类的静态属性(参考http://blog.51cto.com/10836356/2108790),当时就猜测到,是利用的装饰器来完成该功能。那么到底是怎么实现的呢?见下文:
DSC0004.jpg

  在上面的代码中,静态属性的属性是由python内部自己给我们实现的,那么到底它是怎么工作的呢?见下图:
DSC0005.jpg

  此时我们还未进行实例化及调用类的静态属性,见下图:
DSC0006.jpg

  我们可以看到,当进行实例化时,并没有明显差异,但是当调用类的total方法时,就会去调用Myproperty类中的get()方法(此处用到的是描述符优先级的知识,将另开篇幅讲解,此处直接应用),为达到理想的效果,我们只需在get()中进行处理就好,如下图进一步处理:
DSC0007.jpg

  至此,该部分的功能已经完全实现。这就是python在为我们做的工作。那么我们已经理解了原理,这样我们就可以自定义类的其他装饰器。
  该部分代码块如下:
  

class Myproperty():  def __init__(self,fun):
  # print("执行Myproperty类的构造方法")   #调用Myproperty类时会首先运行它
  self.fun = fun
  def __get__(self, instance, owner):
  """
  :param instance: 代表school实例本身
  :param owner:  代表类School本身
  :return:
  """
  # print('调用Myproperty的属性时将执行此方法')
  return  self.fun(instance)
  

  
class School():
  """
  @name:学校名字
  @addr:学校地址
  @price:学费
  @num:招生人数
  """
  def __init__(self,name,addr,price,num):
  self.name =name
  self.addr =addr
  self.price =price
  self.num =num
  # @property
  @Myproperty    #等价于-->>total=Myproperty(total)
  def total(self):
  "求总的学费"
  return  self.price*self.num
  

  
school = School('浙江大学','浙江省杭州市',12000,6000)
  
print(school.total)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-547076-1-1.html 上篇帖子: python代码规范 下篇帖子: Python利用difflib比较字符串
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表