Python3.0之后加入新特性Decorators,以@为标记修饰function和class。有点类似c++的宏和java的注解。Decorators用以修饰约束function和class,分为带参数和不带参数,影响原有输出,例如类静态函数我们要表达的时候需要函数前面加上修饰@staticmethod或@classmethod,为什么这样做呢?下面用简单的例子来看一下,具体内容可以查看:官方解释

不带参数的单一使用

def spamrun(fn):
def sayspam(*args):
print("spam,spam,spam")
fn(*args)
return sayspam
@spamrun
def useful(a,b):
print(a*b) if __name__ == "__main__"
useful(2,5)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果

spam,spam,spam
10
  • 1
  • 2

函数useful本身应该只是打印10,可是为什么最后的结果是这样的呢,其实我们可以简单的把这个代码理解为

def spamrun(fn):
def sayspam(*args):
print("spam,spam,spam")
fn(*args)
return sayspam def useful(a,b):
print(a*b) if __name__ == "__main__"
useful = spamrun(useful)
useful(a,b)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

不带参数的多次使用

def spamrun(fn):
def sayspam(*args):
print("spam,spam,spam")
fn(*args)
return sayspam def spamrun1(fn):
def sayspam1(*args):
print("spam1,spam1,spam1")
fn(*args)
return sayspam1 @spamrun
@spamrun1
def useful(a,b):
print(a*b) if __name__ == "__main__"
useful(2,5)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

运行结果

spam,spam,spam
spam1,spam1,spam1
10
  • 1
  • 2
  • 3

这个代码理解为

if __name__ == "__main__"
useful = spamrun1(spamrun(useful))
useful(a,b)
  • 1
  • 2
  • 3

带参数的单次使用

def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f return decorate @attrs(versionadded="2.2",
author="Guido van Rossum")
def mymethod(f):
print(getattr(mymethod,'versionadded',0))
print(getattr(mymethod,'author',0))
print(f) if __name__ == "__main__"
mymethod(2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

运行结果

2.2
Guido van Rossum
2
  • 1
  • 2
  • 3

这个代码理解为

if __name__ == "__main__"
mymethod = attrs(versionadded="2.2",
author="Guido van Rossum).(mymethod)
mymethod(2)
  • 1
  • 2
  • 3
  • 4

带参数的多次使用 
这次我们来看一个比较实际的例子,检查我们函数的输入输出是否符合我们的标准,比如我们希望的输入是(int,(int,float))输出是(int,float),这个例子在官网里有,但是在3.6版本中使用有些问题,这里进行了一些改动,如果要进一步了解可以看下functionTool。

def accepts(*types):
def check_accepts(f):
def new_f(*args, **kwds):
assert len(types) == (len(args) + len(kwds)), \
"args cnt %d does not match %d" % (len(args) + len(kwds), len(types))
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a, t)
return f(*args, **kwds) update_wrapper(new_f, f)
return new_f return check_accepts def returns(rtype):
def check_returns(f):
def new_f(*args, **kwds):
result = f(*args, **kwds)
assert isinstance(result, rtype), \
"return value %r does not match %s" % (result, rtype)
return result update_wrapper(new_f, f)
return new_f return check_returns @accepts(int, (int, float))
@returns((int, float))
def func(arg1, arg2):
return arg1 * arg2 if __name__ == "__main__"
a = func(1, 'b')
print(a)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

这里故意输入了错误的参数,所以运行结果将我们的断言打印了出来

AssertionError: arg 'b' does not match (<class 'int'>, <class 'float'>)
  • 1

这个代码理解为

if __name__ == "__main__"
func = accepts(int, (int, float)).(accepts((int, float)).(mymethod))
a = func(1, 'b')
print(a)
  • 1
  • 2
  • 3
  • 4

说到这里,大家不难看出其实我们可以使用Decorators做很多工作,简化代码,使逻辑更清晰等。还有更多的用法等着大家自己去挖掘了,这里只简单的介绍了针对函数的用法,其实还可以针对class使用,具体的大家自己看看官方介绍,结合这篇文档应该就不难理解了。

引自:https://blog.csdn.net/u013474436/article/details/75675113

Python自定义注解的更多相关文章

  1. 自定义注解-方法重试@RetryProcess

    背景 在项目开发中,有时候会出现接口调用失败,本身调用又是异步的,如果是因为一些网络问题请求超时,总想可以重试几次把任务处理掉. 一些RPC框架,比如dubbo都是有重试机制的,但是并不是每一个项目多 ...

  2. java自定义注解类

    一.前言 今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下. 二.代码示例 import ...

  3. Jackson 通过自定义注解来控制json key的格式

    Jackson 通过自定义注解来控制json key的格式 最近我这边有一个需求就是需要把Bean中的某一些特殊字段的值进行替换.而这个替换过程是需要依赖一个第三方的dubbo服务的.为了使得这个转换 ...

  4. 自定义注解之运行时注解(RetentionPolicy.RUNTIME)

    对注解概念不了解的可以先看这个:Java注解基础概念总结 前面有提到注解按生命周期来划分可分为3类: 1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成clas ...

  5. JAVA自定义注解

    在学习使用Spring和MyBatis框架的时候,使用了很多的注解来标注Bean或者数据访问层参数,那么JAVA的注解到底是个东西,作用是什么,又怎样自定义注解呢?这篇文章,即将作出简单易懂的解释. ...

  6. 用大白话聊聊JavaSE -- 自定义注解入门

    注解在JavaSE中算是比较高级的一种用法了,为什么要学习注解,我想大概有以下几个原因: 1. 可以更深层次地学习Java,理解Java的思想. 2. 有了注解的基础,能够方便阅读各种框架的源码,比如 ...

  7. [javaSE] 注解-自定义注解

    注解的分类: 源码注解 编译时注解 JDK的@Override 运行时注解 Spring的@Autowired 自定义注解的语法要求 ① 使用@interface关键字定义注解 ② 成员以无参无异常方 ...

  8. 使用spring aspect控制自定义注解

    自定义注解:这里是一个处理异常的注解,当调用方法发生异常时,返回异常信息 /** * ErrorCode: * * @author yangzhenlong * @since 2016/7/21 */ ...

  9. ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存

    基于 ssm + maven + redis 使用自定义注解 利用aop基于AspectJ方式 实现redis缓存 如何能更简洁的利用aop实现redis缓存,话不多说,上demo 需求: 数据查询时 ...

随机推荐

  1. javascript在数组的循环中删除元素

    在开发JavaScript应用的过程中,经常会遇到在循环中移除指定元素的需求. 按照常规的思路,就是对数组进行一个for循环,然后在循环里面进行if判断,在判断中删除掉指定元素即可. 但是实际情况往往 ...

  2. Java8新特性——集合底层源码实现的改变

    ArrayList 源码分析: jdk7: ArrayList list = new ArrayList();//初始化一个长度为10的Object[] elementData sysout(list ...

  3. 如何在Mac上配置iTerm2以及给ITerm2配置lrzsz

    Mac安装ITerm2: https://www.jianshu.com/p/9c3439cc3bdb 给ITerm2配置lrzsz: https://www.cnblogs.com/sunshine ...

  4. Wpf,Unity6

    <?xml version="1.0" encoding="utf-8"?><packages> <package id=&quo ...

  5. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

    本文梯子 本文3.0版本文章 更新 代码已上传Github+Gitee,文末有地址 零.今天完成的绿色部分 一.依赖注入的理解和思考 二.常见的IoC框架有哪些 1.Autofac+原生 2.三种注入 ...

  6. 模板引擎Jinja2的基本用法

    Flask提供的模板引擎为Jinja2,易于使用,功能强大.模板仅仅是文本文件,它可以生成任何基于文本的格式(HTML.XML.CSV.LaTex 等等). 它并没有特定的扩展名, .html 或 . ...

  7. Window常用且通用快捷键

    Ctrl系列: Ctrl +z :回撤,后退 Ctrl +a :全选 Alt系列: Alt+Tab :切换窗口 Window系列 Window+R:打开“运行”窗口 Window+D:显示桌面 其中常 ...

  8. python3+Scrapy爬虫使用pipeline数据保存到文本和数据库,数据少或者数据重复问题

    爬取的数据结果是没有错的,但是在保存数据的时候出错了,出现重复数据或者数据少问题.那为什么会造成这种结果呢? 其原因是由于Spider的速率比较快,而scapy操作数据库操作比较慢,导致pipelin ...

  9. 详解TCP与UDP

    一.TCP的特点 面向连接的.可靠的.基于字节流的传输层通信协议. 将应用层的分割成报文段,并发送发给目标节点的TCP层. 数据包都有序号,对方收到则发送ACK确认,未收到则重传. 使用效验和来效验数 ...

  10. liteos分散加载(十四)

    1. 概述 1.1 基本概念 分散加载是一种实现特定代码快速启动的技术,通过优先加载特定代码到内存,达到缩短从系统开机到特定代码执行的时间.可被应用来实现关键业务的快速启动. 嵌入式系统通过uboot ...