带参数的装饰器动态传值

文章目录

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

​ 有一个函数,返回字符串类型, 现在需要在这个 字符串上添加链接。或者添加一个 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. html js文件域val,js实现文件上传表单域美化特效
  2. PHP获取IP的多种方式解析
  3. 页游开发_小花仙即将出手游,敬童年一起玩过的7K7K和4399
  4. python 读excel中的sheet_Python使用一些背景颜色读取Excel工作表(xlsx)中的单元格?...
  5. 数学--博弈论--巴什博奕(Bash Game)
  6. leetcode310. 最小高度树(bfs)
  7. MySQL查询结果条数编号示例 mysql 查找结果中自动加序号列
  8. 单链表头插法与尾插法的c语言实现(回顾)
  9. treemap比较器_Java TreeMap比较器()方法与示例
  10. Mysql中用between...and...查询日期时注意事项
  11. java 反编译修改软件名字_反编译APK更改文件的文字(修改应用名称)
  12. matlab无法识别VS编译器的办法
  13. 声音均衡器怎么调好听_调音师必备:如何调出最佳人声?
  14. 1、前端背景图自适应
  15. Gramine(原graphene-sgx)软件栈
  16. 有功,无功,视在功率的关系公式和图
  17. 中国移动,电信,联通,铁通,网通的区别与联系
  18. 给猫起名字的几种姿势
  19. 利用python搭建“5433小游戏集成平台”
  20. 排序-------冒泡实现(Java实现)

热门文章

  1. 十四、此次泡沫形成和破裂的原因
  2. 《程序员》07年3期文章试读:网银安全大揭秘—摇摇欲坠的达摩克利期剑
  3. 如何领取赠送的Microsoft Office 家庭学生版
  4. 计算机专业答辩评阅教师评语,指导老师、评阅老师评语及答辩小组评语及评分...
  5. 编写一个程序,求出200到300之间的数,且满足条件:它们三个数字之积为42,三个数字之和为12。
  6. dnf剑魂buff等级上限_DNF:超时空最垃圾的几个职业,剑魂榜上有名,第一炸团必有他...
  7. AdGuard Home更新出错_区服开通时间更新列表
  8. 我的世界服务器怎么修改怪物血量,我的世界命令方块修改生物血量 | 手游网游页游攻略大全...
  9. 反恐精英服务器维护到几点,CSOL4月22日更新维护公告 停机维护到几点
  10. 这样的财务报表分析软件谁不爱!帮你轻松搞定财务问题~