如何用python的装饰器定义一个像C++一样的强类型函数
def fun(a:int, b=1, *c, d, e=2, **f) -> str:
pass
这里主要是说几点与python2中不同的点。





# _*_ coding: utf-8
import functools
import inspect
from itertools import chain def typesafe(func):
"""
Verify that the function is called with the right arguments types and that
it returns a value of the right type, accordings to its annotations.
"""
spec = inspect.getfullargspec(func)
annotations = spec.annotations for name, annotation in annotations.items():
if not isinstance(annotation, type):
raise TypeError("The annotation for '%s' is not a type." % name) error = "Wrong type for %s: expected %s, got %s."
# Deal with default parameters
defaults = spec.defaults or ()
defaults_zip = zip(spec.args[-len(defaults):], defaults)
kwonlydefaults = spec.kwonlydefaults or {}
for name, value in chain(defaults_zip, kwonlydefaults.items()):
if name in annotations and not isinstance(value, annotations[name]):
raise TypeError(error % ('default value of %s' % name,
annotations[name].__name__,
type(value).__name__)) @functools.wraps(func)
def wrapper(*args, **kwargs):
# Populate a dictionary of explicit arguments passed positionally
explicit_args = dict(zip(spec.args, args))
keyword_args = kwargs.copy()
# Add all explicit arguments passed by keyword
for name in chain(spec.args, spec.kwonlyargs):
if name in kwargs:
explicit_args[name] = keyword_args.pop(name) # Deal with explict arguments
for name, arg in explicit_args.items():
if name in annotations and not isinstance(arg, annotations[name]):
raise TypeError(error % (name,
annotations[name].__name__,
type(arg).__name__)) # Deal with variable positional arguments
if spec.varargs and spec.varargs in annotations:
annotation = annotations[spec.varargs]
for i, arg in enumerate(args[len(spec.args):]):
if not isinstance(arg, annotation):
raise TypeError(error % ('variable argument %s' % (i+1),
annotation.__name__,
type(arg).__name__)) # Deal with variable keyword argument
if spec.varkw and spec.varkw in annotations:
annotation = annotations[spec.varkw]
for name, arg in keyword_args.items():
if not isinstance(arg, annotation):
raise TypeError(error % (name,
annotation.__name__,
type(arg).__name__)) # Deal with return value
r = func(*args, **kwargs)
if 'return' in annotations and not isinstance(r, annotations['return']):
raise TypeError(error % ('the return value',
annotations['return'].__name__,
type(r).__name__))
return r return wrapper
对于上面的代码:
# _*_ coding: utf-8
import functools
import inspect
from itertools import chain def precessArg(value, annotation):
try:
return annotation(value)
except ValueError as e:
print('value:', value)
raise TypeError('Expected: %s, got: %s' % (annotation.__name__,
type(value).__name__)) def typesafe(func):
"""
Verify that the function is called with the right arguments types and that
it returns a value of the right type, accordings to its annotations.
"""
spec = inspect.getfullargspec(func)
annotations = spec.annotations for name, annotation in annotations.items():
if not isinstance(annotation, type):
raise TypeError("The annotation for '%s' is not a type." % name) error = "Wrong type for %s: expected %s, got %s."
# Deal with default parameters
defaults = spec.defaults and list(spec.defaults) or []
defaults_zip = zip(spec.args[-len(defaults):], defaults)
i = 0
for name, value in defaults_zip:
if name in annotations:
defaults[i] = precessArg(value, annotations[name])
i += 1
func.__defaults__ = tuple(defaults) kwonlydefaults = spec.kwonlydefaults or {}
for name, value in kwonlydefaults.items():
if name in annotations:
kwonlydefaults[name] = precessArg(value, annotations[name])
func.__kwdefaults__ = kwonlydefaults @functools.wraps(func)
def wrapper(*args, **kwargs):
keyword_args = kwargs.copy()
new_args = args and list(args) or []
new_kwargs = kwargs.copy()
# Deal with explicit argument passed positionally
i = 0
for name, arg in zip(spec.args, args):
if name in annotations:
new_args[i] = precessArg(arg, annotations[name])
i += 1 # Add all explicit arguments passed by keyword
for name in chain(spec.args, spec.kwonlyargs):
poped_name = None
if name in kwargs:
poped_name = keyword_args.pop(name)
if poped_name is not None and name in annotations:
new_kwargs[name] = precessArg(poped_name, annotations[name]) # Deal with variable positional arguments
if spec.varargs and spec.varargs in annotations:
annotation = annotations[spec.varargs]
for i, arg in enumerate(args[len(spec.args):]):
new_args[i] = precessArg(arg, annotation) # Deal with variable keyword argument
if spec.varkw and spec.varkw in annotations:
annotation = annotations[spec.varkw]
for name, arg in keyword_args.items():
new_kwargs[name] = precessArg(arg, annotation) # Deal with return value
r = func(*new_args, **new_kwargs)
if 'return' in annotations:
r = precessArg(r, annotations['return'])
return r return wrapper if __name__ == '__main__':
print("Begin test.")
print("Test case 1:")
try:
@typesafe
def testfun1(a:'This is a para.'):
print('called OK!')
except TypeError as e:
print("TypeError: %s" % e) print("Test case 2:")
try:
@typesafe
def testfun2(a:int,b:str = 'defaule'):
print('called OK!')
testfun2('str',1)
except TypeError as e:
print("TypeError: %s" % e) print("test case 3:")
try:
@typesafe
def testfun3(a:int, b:int = 'str'):
print('called OK')
except TypeError as e:
print('TypeError: %s' % e) print("Test case 4:")
try:
@typesafe
def testfun4(a:int = '', b:int = 1.2):
print('called OK.')
print(a, b)
testfun4()
except TypeError as e:
print('TypeError: %s' % e) @typesafe
def testfun5(a:int, b, c:int = 1, d = 2, *e:int, f:int, g, h:int = 3, i = 4, **j:int) -> str :
print('called OK.')
print(a, b, c, d, e, f, g, h, i, j)
return 'OK' print("Test case 5:")
try:
testfun5(1.2, 'whatever', f = 2.3, g = 'whatever')
except TypeError as e:
print('TypeError: %s' % e) print("Test case 6:")
try:
testfun5(1.2, 'whatever', 2.2, 3.2, 'e1', f = '', g = 'whatever')
except TypeError as e:
print('TypeError: %s' % e) print("Test case 7:")
try:
testfun5(1.2, 'whatever', 2.2, 3.2, 12, f = '', g = 'whatever')
except TypeError as e:
print('TypeError: %s' % e) print("Test case 8:")
try:
testfun5(1.2, 'whatever', 2.2, 3.2, 12, f = '', g = 'whatever', key1 = 'key1')
except TypeError as e:
print('TypeError: %s' % e) print("Test case 9:")
try:
testfun5(1.2, 'whatever', 2.2, 3.2, 12, f = '', g = 'whatever', key1 = '')
except TypeError as e:
print('TypeError: %s' % e) print('Test case 10:')
@typesafe
def testfun10(a) -> int:
print('called OK.')
return 'OK'
try:
testfun10(1)
except TypeError as e:
print('TypeError: %s' % e)
如何用python的装饰器定义一个像C++一样的强类型函数的更多相关文章
- $python用装饰器实现一个计时器
直接上代码: import time from functools import wraps # 定义装饰器 def fn_timer(function): @wraps(function) def ...
- python基础—装饰器
python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...
- 【Python】装饰器理解
以下文章转载自:点这里 关于装饰器相关的帖子记录在这里: 廖雪峰, thy专栏, stackflow Python的函数是对象 简单的例子: def shout(word="yes" ...
- Python之装饰器、迭代器和生成器
在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思 ...
- 关于python的装饰器(初解)
在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...
- 如何写一个Python万能装饰器,既可以装饰有参数的方法,也可以装饰无参数方法,或者有无返回值都可以装饰
Python中的装饰器,可以有参数,可以有返回值,那么如何能让这个装饰器既可以装饰没有参数没有返回值的方法,又可以装饰有返回值或者有参数的方法呢?有一种万能装饰器,代码如下: def decorate ...
- 第7.27节 Python案例详解: @property装饰器定义属性访问方法getter、setter、deleter
上节详细介绍了利用@property装饰器定义属性的语法,本节通过具体案例来进一步说明. 一. 案例说明 本节的案例是定义Rectangle(长方形)类,为了说明问题,除构造函数外,其他方法都只 ...
- 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解
第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一. 引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...
- Python使用property函数和使用@property装饰器定义属性访问方法的异同点分析
Python使用property函数和使用@property装饰器都能定义属性的get.set及delete的访问方法,他们的相同点主要如下三点: 1.定义这些方法后,代码中对相关属性的访问实际上都会 ...
随机推荐
- 《马上有招儿:PPT商务演示精选20讲(全彩) 》
<马上有招儿:PPT商务演示精选20讲(全彩) > 基本信息 作者:马建强 霍然 出版社:电子工业出版社 ISBN:9787121225123 上架时间:2014-3-11 出版日期 ...
- 采用Operator-sdk轻松将helm chart转为Operator
去年就接触Operator,从Oracle发布的WebLogic Operator到mySQL Operator,构建的源码一大堆,但感觉一直缺少合适的开发框架能够避免复杂性快速生成, 随着技术的日益 ...
- 混沌数学之离散点集图形DEMO
最近看了很多与混沌相关的知识,并写了若干小软件.混沌现象是个有意思的东西,同时混沌也能够生成许多有意思的图形.混沌学的现代研究使人们渐渐明白,十分简单的数学方程完全可以模拟系统如瀑布一样剧烈的行为.输 ...
- Mysql数据库事务及隔离级别学习测试
参考了这篇文章的一些内容: http://xm-king.iteye.com/blog/770721 记住以下这张表: 我在springdemo库里面建了一个表: CREATE TABLE `tx` ...
- tomcat 用AXIS2发布WebService 网站的方法
Axis2+tomcat7.0 实现webService 服务端发布与客户端的调用. Aixs2开发webService的方法有很多,在此只介绍一种比较简单的实现方法. 第一步:首先要下载开发所需要的 ...
- Nginx配置文件(nginx.conf)配置具体解释
欢迎扫码增加Java高知群交流 Nginx的配置文件nginx.conf配置具体解释例如以下: user nginx nginx ; Nginx用户及组:用户 组. window下不指定 wo ...
- 【架构】Kubernetes和Spring Cloud哪个部署微服务更好?
Spring Cloud 和Kubernetes都自称自己是部署和运行微服务的最好环境,但是它们在本质上和解决不同问题上是有很大差异的.在本文中,我们将看到每个平台如何帮助交付基于微服务的架构(MSA ...
- Cognos值提示设置小技巧
针对值提示问题做一个小的总结: 1:显示类问题 如上图,如何让”英文参数名"和"分割线----"不显示,或者说指定中文显示值呢 (1):让”英文参数名"和&qu ...
- 【5】基于Log4Net的日志系统
阅读目录 日志系统应具备的特性 Log4Net 配置文件:log4net.config 初始化 输出信息 对Log4Net的封装 log4net.config复杂配置 不管是Web应用程序还是W ...
- IStat Menus 5.02 5.03 的注册码
1574-5977-7956-8062-0000 6015-5448-3282-4975-0000 9665-5955-6856-2071-0000 2447-9517-7939-5221-0000