带参数的装饰器动态传值

文章目录

  • 带参数的装饰器动态传值
    • 装饰器实现的简单实现
    • 装饰器参数动态传入值
    • 把装饰器实例方法 改成静态方法
    • 装饰器函数写类的外面
    • 总结一下

​ 有一个函数,返回字符串类型, 现在需要在这个 字符串上添加链接。或者添加一个 p 标签 , 这里很容易想到可以用一个装饰器来完成这个任务。

装饰器实现的简单实现

相信很多的同学,都可以想到,这个还不简单 直接使用带参数的装饰器 不就可以搞定了。

# -*- coding: utf-8 -*-
from functools import wraps
from typing import Dict"""
pip install pysimple-log==0.0.4
"""
from simplelog import loggerdef add_custom_tag(tagname='', attrs: Dict = None):"""目前支持 添加  a 标签, p 标签:param tagname::param attrs::return:"""if attrs is None:attrs = {}def _add_tag(fn):@wraps(fn)def wrapper(*args, **kwargs):r = fn(*args, **kwargs)if tagname == 'p':return '<p>' + str(r) + '</p>'elif tagname == 'a':href = attrs.pop('href', '')rel = attrs.pop('rel', '')first = f'<a href={href!r} rel={rel!r}>'tail = '</a>'result = first + str(r) + tailreturn resultelse:logger.info(f'Unkonwn tag:{tagname!r}')return rreturn wrapperreturn _add_tagclass Model:@add_custom_tag(tagname='a', attrs={'href': 'https://www.offical.version','rel': "noopener noreferrer nofollow",})def first_official(self):return "official version"@add_custom_tag(tagname='p')def second_para(self):return "This is a paragraph"if __name__ == '__main__':model = Model()r2 = model.first_official()print(r2)r3 = model.second_para()print(r3)

add_custom_tag 这里定义一个装饰器, 如果 传入tagname 为 a 标签,就给函数的返回值 添加 a 标签, 同时 attrs 表示 当前标签的属性。

Mode 类中定义了两个函数,一个first_official 希望给这个函数返回值 添加一个a 标签, 属性有两个 href , rel 属性对应的值分别为 https://www.offical.versionnoopener noreferrer nofollow 。 然后还有一个 函数 希望添加p 标签,没有属性。

跑一下 代码结果如下:

一切都很正常, 装饰器完成了期待的功能。

那么现在有一个问题来了, 被装饰器装饰的两个函数 first_officialsecond_para 通过传入参数 tagname , attrs 来给标签添加属性值。 这里有一个问题, 在装饰器 要修饰的函数first_official 我们要知道 给这个函数返回值 添加 a 标签, 并且需要传入 attrs ,里面有一个属性 href 代表 要添加的链接。

注意 红色框里面的,就是我们添加a 标签 , 同时要传入一个href ,对应一个链接的值。 有的时候 我们 可能不想 那么快给这个标签 一个链接, 而是 Model 类 完成一些操作之后 ,来动态获取这个值,而不是确定一个值。 不知道我有没有 说明白, href 这个值是可以变化的而,不是固定一个值。

装饰器参数动态传入值

假设 Model 类 是获取页面的url ,获取页面不同位置的url

# -*- coding: utf-8 -*-
from functools import wraps
from typing import Dict"""
pip install pysimple-log==0.0.4
"""
from simplelog import loggerclass Model:def __init__(self, ):self._all_url_map = {}@propertydef all_url_map(self):if not self._all_url_map:self.craw_urls()return self._all_url_mapdef craw_urls(self) -> Dict[str, str]:"""这里我需要动态获取的url,模拟抓取URL:return:"""# mock dataresult = {'table_of_contents': 'https://www.content','version': 'https://www.official.version','memorandum': 'https://www.memorandum',}self._all_url_map = resultreturn resultdef add_custom_tag(self, tagname='', attrs: Dict = None):"""目前支持 添加  a 标签, p 标签:param tagname::param attrs::return:"""if attrs is None:attrs = {}def _add_tag(fn):@wraps(fn)def wrapper(self, *args, **kwargs):r = fn(self, *args, **kwargs)fun_name = fn.__name__logger.info(f"fun_name:{fun_name}")if tagname == 'p':return '<p>' + str(r) + '</p>'elif tagname == 'a':if fun_name == '_first_official':href = self.all_url_map['version']elif fun_name == '_the_third_explanatory_memorandum':href = self.all_url_map['memorandum']else:logger.info(f'Unkown function_name: {fun_name!r}')href = attrs.pop('href', '')rel = attrs.pop('rel', '')first = f'<a href={href!r} rel={rel!r}>'tail = '</a>'result = first + str(r) + tailreturn resultelse:print(f'Unkonwn tag:{tagname!r}')return rreturn wrapperreturn _add_tag@add_custom_tag(self='self', tagname='a', attrs={'href': 'xxxxxx','rel': "noopener noreferrer nofollow",})def _first_official(self):return "official version"@add_custom_tag(self='self', tagname='a', attrs={'href': 'xxx','rel': "noopener noreferrer nofollow",})def _the_third_explanatory_memorandum(self):return "the explanatory memorandum"@add_custom_tag(self='self', tagname='p')def _sec_para(self):return 'hello world'def parse_further_reading(self):""":return:"""first = self._first_official()sec = self._sec_para()third = self._the_third_explanatory_memorandum()return first + sec + thirdif __name__ == '__main__':model = Model()r3 = model.parse_further_reading()print(r3)

这里模拟抓取url

这里 注意 我们刚刚的装饰器 放入了,Model 类里面, 然后添加self 这个变量。 这样就可以通过 model 来动态抓取URL, 来改变 href 的值了。

然后调用的时候 我并不需要传入这个href ,但是要传入这个key ,href ,注意这里我用'xxx' 表示一个url

在装饰器里面实现的时候,通过 被装饰的函数名,来动态的绑定 url ,这个url 是从网页抓取而来, 这里craw_url 这个方法 来模拟实现 抓取url 。

让我们来测试一下整个代码:

从结果上面看已经可以正常实现了,url 就是通过 craw_url 来抓取的值,来完成的。

把装饰器实例方法 改成静态方法

注意到装饰器里面传入一个'self' 感觉奇怪 ,可以把装饰器定义成静态方法。

但是调用的时候,会报错 TypeError: 'staticmethod' object is not callable

add_custom_tag = add_custom_tag.__func__ 还是要强行转一下。

from functools import wraps
from typing import Dict"""
pip install pysimple-log==0.0.4
"""
from simplelog import loggerclass Model:def __init__(self, ):self._all_url_map = {}@propertydef all_url_map(self):if not self._all_url_map:self.craw_urls()return self._all_url_mapdef craw_urls(self) -> Dict[str, str]:"""这里我需要动态获取的url,模拟抓取URL:return:"""# mock dataresult = {'table_of_contents': 'https://www.content','version': 'https://www.official.version','memorandum': 'https://www.memorandum',}self._all_url_map = resultreturn result@staticmethoddef add_custom_tag(tagname='', attrs: Dict = None):"""目前支持 添加  a 标签, p 标签:param tagname::param attrs::return:"""if attrs is None:attrs = {}def _add_tag(fn):@wraps(fn)def wrapper(self, *args, **kwargs):r = fn(self, *args, **kwargs)fun_name = fn.__name__logger.info(f"fun_name:{fun_name}")if tagname == 'p':return '<p>' + str(r) + '</p>'elif tagname == 'a':if fun_name == '_first_official':href = self.all_url_map['version']elif fun_name == '_the_third_explanatory_memorandum':href = self.all_url_map['memorandum']else:logger.info(f'Unkown function_name: {fun_name!r}')href = attrs.pop('href', '')rel = attrs.pop('rel', '')first = f'<a href={href!r} rel={rel!r}>'tail = '</a>'result = first + str(r) + tailreturn resultelse:logger.info(f'Unkonwn tag:{tagname!r}')return rreturn wrapperreturn _add_tag# 把静态方法 转成 functionadd_custom_tag = add_custom_tag.__func__@add_custom_tag(tagname='a', attrs={'href': 'xxxxxx','rel': "noopener noreferrer nofollow",})def _first_official(self):return "official version"@add_custom_tag(tagname='a', attrs={'href': 'xxx','rel': "noopener noreferrer nofollow",})def _the_third_explanatory_memorandum(self):return "the explanatory memorandum"@add_custom_tag(tagname='p')def _sec_para(self):return 'hello world'def parse_further_reading(self):""":return:"""first = self._first_official()sec = self._sec_para()third = self._the_third_explanatory_memorandum()return first + sec + third

这样看起来是好一些。同时也完成了 url 先传入,后赋值的功能。

装饰器函数写类的外面

把装饰器 写在类的外面,其实这个装饰器 本质上和类 没有关系, 只是想获取类的实例对象,取到 url 值而已。

from functools import wraps
from typing import Dict"""
pip install pysimple-log==0.0.4
"""
from simplelog import loggerdef add_custom_tag(tagname='', attrs: Dict = None):"""目前支持 添加  a 标签, p 标签:param tagname::param attrs::return:"""if attrs is None:attrs = {}def _add_tag(fn):@wraps(fn)def wrapper(self, *args, **kwargs):r = fn(self, *args, **kwargs)fun_name = fn.__name__logger.info(f"fun_name:{fun_name}")if tagname == 'p':return '<p>' + str(r) + '</p>'elif tagname == 'a':if fun_name == '_first_official':href = self.all_url_map['version']elif fun_name == '_the_third_explanatory_memorandum':href = self.all_url_map['memorandum']else:logger.info(f'Unkown function_name: {fun_name!r}')href = attrs.pop('href', '')rel = attrs.pop('rel', '')first = f'<a href={href!r} rel={rel!r}>'tail = '</a>'result = first + str(r) + tailreturn resultelse:logger.info(f'Unkonwn tag:{tagname!r}')return rreturn wrapperreturn _add_tagclass Model:def __init__(self, ):self._all_url_map = {}@propertydef all_url_map(self):if not self._all_url_map:self.craw_urls()return self._all_url_mapdef craw_urls(self) -> Dict[str, str]:"""这里我需要动态获取的url,模拟抓取URL:return:"""# mock dataresult = {'table_of_contents': 'https://www.content','version': 'https://www.official.version','memorandum': 'https://www.memorandum',}self._all_url_map = resultreturn result# 把 静态方法转成 function# add_custom_tag = add_custom_tag.__func__@add_custom_tag(tagname='a', attrs={'href': 'xxxxxx','rel': "noopener noreferrer nofollow",})def _first_official(self):return "official version"@add_custom_tag(tagname='a', attrs={'href': 'xxx','rel': "noopener noreferrer nofollow",})def _the_third_explanatory_memorandum(self):return "the explanatory memorandum"@add_custom_tag(tagname='p')def _sec_para(self):return 'hello world'def parse_further_reading(self):""":return:"""first = self._first_official()sec = self._sec_para()third = self._the_third_explanatory_memorandum()return first + sec + thirdif __name__ == '__main__':model = Model()r3 = model.parse_further_reading()print(r3)

通过 self 作为 wrapper 的参数 即可, 这样就可以获取 self。 即类的实例对象, 然后就可以进行其他的操作了。

总结一下

​ 有点时候希望装饰器是带参数的, 但是参数的值,并不是一开始就是确定的, 那么我们就可以使用这种方法,来动态改变该值。

分享快乐,留住感动. '2021-03-12 20:48:33' 第二次更新 --frank
分享快乐,留住感动. '2021-03-07 17:59:43' --frank

装饰器-带参数的装饰器动态传值相关推荐

  1. python 装饰器 参数-[Python]写个带参数的装饰器

    上篇文章 Python装饰器为什么难理解?从函数到装饰器一步一步介绍了Python装饰器的来由,不知你对装饰器理解了没有,强烈建议你自己动手写个装饰器应用到项目中加深理解.装饰器可以很简单,也可以很复 ...

  2. python全栈学习--day12(函数高级应用-带参数的装饰器,多个装饰器装饰一个函数)...

    函数的执行时,*打散 函数的定义时,*聚合 from functools import wrapsdef wrapper(f):@wraps(f)def inner(*args,**kwargs):' ...

  3. python装饰器传递参数_Python装饰器高级版—Python类内定义装饰器并传递self参数...

    本文重点:解决了类里面定义的装饰器,在同一个类里面使用的问题,并实现了装饰器的类属性参数传递 目录: 一.基本装饰器 二.在类里定义装饰器,装饰本类内函数 三.类装饰器 正文: 一.基本装饰器 装饰不 ...

  4. Python带参数的装饰器

    在装饰器函数里传入参数 # -*- coding: utf-8 -*- # 2017/12/2 21:38 # 这不是什么黑魔法,你只需要让包装器传递参数: def a_decorator_passi ...

  5. python装饰器模式带参数_python函数装饰器、类装饰器和带参数的装饰器——装饰器模式...

    装饰器模式: 动态地给对象添加一些额外的职责,就增加功能来说,装饰模式比生产子类更加灵活 Component 是定义一个对象接口,可以给这些对象动态地添加职责.concreteComponent是定义 ...

  6. python 装饰器 参数-python函数装饰器之带参数的函数和带参数的装饰器用法示例...

    本文实例讲述了python函数装饰器之带参数的函数和带参数的装饰器用法.分享给大家供大家参考,具体如下: 1. 函数带多个参数 # 普通的装饰器, 打印函数的运行时间 def decrator(fun ...

  7. python 装饰器 参数-Python装饰器(4)带参数的装饰器

    内容纯属个人理解,不对之处,欢迎指正. 之前说过,装饰器其实就是函数,既然是函数,那就可以有参数,装饰器也不例外,接下来我们来分析带参数的装饰器. 如何构造带参数 带参数倒是很简单,在装饰的时候给装饰 ...

  8. python装饰器函数-python函数装饰器之带参数的函数和带参数的装饰器用法示例

    本文实例讲述了python函数装饰器之带参数的函数和带参数的装饰器用法.分享给大家供大家参考,具体如下: 1. 函数带多个参数 # 普通的装饰器, 打印函数的运行时间 def decrator(fun ...

  9. python带参数的装饰器_Python-----带参数的装饰器以及补充

    带参数的装饰器 def wrapper_out(n): # def wrapper(f): # def inner(*args,**kwargs): # # if n == 'qq': # # use ...

最新文章

  1. CentOS7系统ifconfig无法使用的解决方法
  2. 深度学习100例-卷积神经网络(CNN)花朵识别 | 第4天
  3. RabbitMQ Topic交换机(结果成功)
  4. Leet Code OJ 260. Single Number III [Difficulty: Medium]
  5. 7-118 估值一亿的AI核心代码 (20 分)
  6. 三维立体动画制作_三维立体动画制作相比传统方式的特点
  7. 一文搞懂 CPU、GPU 和 TPU
  8. 任务58:19-尚硅谷-Java语言基础-String类型变量的使用
  9. 渗透-N种反弹shell方法
  10. 树莓派+ L298N 控制二相四线步进电机
  11. 使用阿里云发送短信验证码教程(简单易学)
  12. sis地址发布器_【一起练翻译-9.1】关于提词器、真实、川普和演讲
  13. 默默学Sharding-Sphere(一)
  14. 热评云厂商:青云科技4.29亿元,重研发押注更大发展
  15. 计算机无法屏幕亮度,今天详解win10电脑屏幕亮度无法调节的具体解决手法
  16. 如何针对时间片论法进行优化
  17. 前端html页面中的命名规范
  18. char **和char* []区别,char *和char []区别
  19. 【每天一个Linux命令】09. Linux中chown的用法
  20. LeetCode 每日一题 42. 接雨水 详细多种题解 C++描述

热门文章

  1. Linux如何配置nVIDIA显卡驱动
  2. python设计查询余额程序_python实现监控阿里云账户余额功能
  3. Java设计六大原则
  4. Windows CE显示驱动分析
  5. 零基础python嵌入式开发_python写嵌入式
  6. 《华林科纳-半导体工艺》颗粒清洗技术
  7. linux图像界面和命令界面切换:
  8. 人工智能之配置环境教程一:安装VsCode和Anaconda
  9. 跑跑卡丁车登录提示服务器无响应怎么办,跑跑卡丁车登陆问题
  10. 西安Java培训 | java设计模式之工厂设计模式