首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >python 对传参进行参数检查的装饰器

python 对传参进行参数检查的装饰器

作者头像
用户5760343
发布于 2019-12-12 08:26:08
发布于 2019-12-12 08:26:08
97400
代码可运行
举报
文章被收录于专栏:sktjsktj
运行总次数:0
代码可运行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from inspect import signature
 from functools import wraps
def typeassert(*ty_args, **ty_kwargs):
 def decorate(func):
 # If in optimized mode, disable type checking
 if not debug:
 return func
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # Map function argument names to supplied types
    sig = signature(func)
    bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments

    @wraps(func)
    def wrapper(*args, **kwargs):
        bound_values = sig.bind(*args, **kwargs)
        # Enforce type assertions across supplied arguments
        for name, value in bound_values.arguments.items():
            if name in bound_types:
                if not isinstance(value, bound_types[name]):
                    raise TypeError(
                        'Argument {} must be {}'.format(name, bound_types[name])
                        )
        return func(*args, **kwargs)
    return wrapper
return decorate

调用方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   @typeassert(int, z=int)
 ... def spam(x, y, z=42):
 ...     print(x, y, z)
 ...
 spam(1, 2, 3)
 1 2 3
 spam(1, 'hello', 3)
 1 hello 3
 spam(1, 'hello', 'world')
 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "contract.py", line 33, in wrapper
 TypeError: Argument z must be <class 'int'>
 
 
 

装饰器说明

首先,装饰器只会在函数定义时被调用一次。 有时候你去掉装饰器的功能,那么你只需要简单的返回被装饰函数即可。 下面的代码中,如果全局变量 debug 被设置成了False(当你使用-O或-OO参数的优化模式执行程序时), 那么就直接返回未修改过的函数本身:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def decorate(func):
 # If in optimized mode, disable type checking
 if not debug:
 return func
 其次,这里还对被包装函数的参数签名进行了检查,我们使用了 inspect.signature() 函数。 简单来讲,它运行你提取一个可调用对象的参数签名信息。例如:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   from inspect import signature
 def spam(x, y, z=42):
 ...     pass
 ...
 sig = signature(spam)
 print(sig)
 (x, y, z=42)
 sig.parameters
 mappingproxy(OrderedDict([('x', <Parameter at 0x10077a050 'x'>),
 ('y', <Parameter at 0x10077a158 'y'>), ('z', <Parameter at 0x10077a1b0 'z'>)]))
 sig.parameters['z'].name
 'z'
 sig.parameters['z'].default
 42
 sig.parameters['z'].kind
 <_ParameterKind: 'POSITIONAL_OR_KEYWORD'>
 
 
 

装饰器的开始部分,我们使用了 bind_partial() 方法来执行从指定类型到名称的部分绑定。 下面是例子演示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   bound_types = sig.bind_partial(int,z=int)
 bound_types
 <inspect.BoundArguments object at 0x10069bb50>
 bound_types.arguments
 OrderedDict([('x', <class 'int'>), ('z', <class 'int'>)])
 
 
 

在这个部分绑定中,你可以注意到缺失的参数被忽略了(比如并没有对y进行绑定)。 不过最重要的是创建了一个有序字典 bound_types.arguments 。 这个字典会将参数名以函数签名中相同顺序映射到指定的类型值上面去。 在我们的装饰器例子中,这个映射包含了我们要强制指定的类型断言。

在装饰器创建的实际包装函数中使用到了 sig.bind() 方法。 bind() 跟 bind_partial() 类似,但是它不允许忽略任何参数。因此有了下面的结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   bound_values = sig.bind(1, 2, 3)
 bound_values.arguments
 OrderedDict([('x', 1), ('y', 2), ('z', 3)])
 
 
 

使用这个映射我们可以很轻松的实现我们的强制类型检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   for name, value in bound_values.arguments.items():
 ...     if name in bound_types.arguments:
 ...         if not isinstance(value, bound_types.arguments[name]):
 ...             raise TypeError()
 ...
 
 
 

不过这个方案还有点小瑕疵,它对于有默认值的参数并不适用。 比如下面的代码可以正常工作,尽管items的类型是错误的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   @typeassert(int, list)
 ... def bar(x, items=None):
 ...     if items is None:
  sig = signature(spam)
 >>> print(sig)
 (x, y, z=42)
 >>> sig.parameters
 mappingproxy(OrderedDict([('x', <Parameter at 0x10077a050 'x'>),
 ('y', <Parameter at 0x10077a158 'y'>), ('z', <Parameter at 0x10077a1b0 'z'>)]))
 >>> sig.parameters['z'].name
 'z'
 >>> sig.parameters['z'].default
 42
 >>> sig.parameters['z'].kind
 <_ParameterKind: 'POSITIONAL_OR_KEYWORD'>
 >>>
 装饰器的开始部分,我们使用了 bind_partial() 方法来执行从指定类型到名称的部分绑定。 下面是例子演示:
 
 >>> bound_types = sig.bind_partial(int,z=int)
 >>> bound_types
 <inspect.BoundArguments object at 0x10069bb50>
 >>> bound_types.arguments
 OrderedDict([('x', <class 'int'>), ('z', <class 'int'>)])
 >>>
 在这个部分绑定中,你可以注意到缺失的参数被忽略了(比如并没有对y进行绑定)。 不过最重要的是创建了一个有序字典 bound_types.arguments 。 这个字典会将参数名以函数签名中相同顺序映射到指定的类型值上面去。 在我们的装饰器例子中,这个映射包含了我们要强制指定的类型断言。
 
 在装饰器创建的实际包装函数中使用到了 sig.bind() 方法。 bind()bind_partial() 类似,但是它不允许忽略任何参数。因此有了下面的结果:
 
 >>> bound_values = sig.bind(1, 2, 3)
 >>> bound_values.arguments
 OrderedDict([('x', 1), ('y', 2), ('z', 3)])
 >>>
 使用这个映射我们可以很轻松的实现我们的强制类型检查:
 
 >>> for name, value in bound_values.arguments.items():
 ...     if name in bound_types.arguments:
 ...         if not isinstance(value, bound_types.arguments[name]):
 ...             raise TypeError()
 ...
 >>>
 不过这个方案还有点小瑕疵,它对于有默认值的参数并不适用。 比如下面的代码可以正常工作,尽管items的类型是错误的:
 
 >>> @typeassert(int, list)
 ... def bar(x, items=None):
 ...     if items is None:
 ...         items = []
 ...     items.append(x)
 ...     return items
 bar(2)
 [2]
 bar(2,3)
 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "contract.py", line 33, in wrapper
 TypeError: Argument items must be <class 'list'>
 bar(4, [1, 2, 3])
 sig.parameters['z'].kind
 <_ParameterKind: 'POSITIONAL_OR_KEYWORD'>
 >>>
 装饰器的开始部分,我们使用了 bind_partial() 方法来执行从指定类型到名称的部分绑定。 下面是例子演示:
 
 >>> bound_types = sig.bind_partial(int,z=int)
 >>> bound_types
 <inspect.BoundArguments object at 0x10069bb50>
 >>> bound_types.arguments
 OrderedDict([('x', <class 'int'>), ('z', <class 'int'>)])
 >>>
 在这个部分绑定中,你可以注意到缺失的参数被忽略了(比如并没有对y进行绑定)。 不过最重要的是创建了一个有序字典 bound_types.arguments 。 这个字典会将参数名以函数签名中相同顺序映射到指定的类型值上面去。 在我们的装饰器例子中,这个映射包含了我们要强制指定的类型断言。
 
 在装饰器创建的实际包装函数中使用到了 sig.bind() 方法。 bind()bind_partial() 类似,但是它不允许忽略任何参数。因此有了下面的结果:
 
 >>> bound_values = sig.bind(1, 2, 3)
 >>> bound_values.arguments
 OrderedDict([('x', 1), ('y', 2), ('z', 3)])
 >>>
 使用这个映射我们可以很轻松的实现我们的强制类型检查:
 
 >>> for name, value in bound_values.arguments.items():
 ...     if name in bound_types.arguments:
 ...         if not isinstance(value, bound_types.arguments[name]):
 ...             raise TypeError()
 ...
 >>>
 不过这个方案还有点小瑕疵,它对于有默认值的参数并不适用。 比如下面的代码可以正常工作,尽管items的类型是错误的:
 
 >>> @typeassert(int, list)
 ... def bar(x, items=None):
 ...     if items is None:
 ...         items = []
 ...     items.append(x)
 ...     return items
 >>> bar(2)
 [2]
 >>> bar(2,3)
 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "contract.py", line 33, in wrapper
 TypeError: Argument items must be <class 'list'>
 >>> bar(4, [1, 2, 3])
 [1, 2, 3, 4]
 
 
 
 

最后一点是关于适用装饰器参数和函数注解之间的争论。 例如,为什么不像下面这样写一个装饰器来查找函数中的注解呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@typeassert
 def spam(x:int, y, z:int = 42):
 print(x,y,z)
 一个可能的原因是如果使用了函数参数注解,那么就被限制了。 如果注解被用来做类型检查就不能做其他事情了。而且 @typeassert 不能再用于使用注解做其他事情的函数了。 而使用上面的装饰器参数灵活性大多了,也更加通用。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
局域网SDN技术硬核内幕 - 16 三 从物到人 园区用户漫游的EVPN实现
昨天我们提到了,一些厂商发现,通过MPLS V**可以实现园区网络的切片,把不同组的用户加入不同切片,来实现权限跟随用户。
用户8289326
2022/07/22
5370
局域网SDN技术硬核内幕 - 16 三 从物到人 园区用户漫游的EVPN实现
局域网SDN硬核技术内幕 17 从一到百
“无生一,一生二,二生三,三生万物”。老祖宗们的智慧,在ICT界得到了最好的诠释。
用户8289326
2022/07/22
3030
局域网SDN硬核技术内幕 17 从一到百
网络设备硬核技术内幕 交换机篇 15 辟邪剑谱 (中)
昨天我们看到,魔教获得葵花宝典的片段后,将其整合为辟邪剑谱,在数据中心交换机中使用性能较低的交换芯片ENP,导致无法实现线速转发。
用户8289326
2022/07/27
6441
网络设备硬核技术内幕 交换机篇 15 辟邪剑谱 (中)
网络设备硬核技术内幕 交换机篇 16 辟邪剑法(下)
上回说到,自从黑木崖大规模招降纳叛,在江湖上混不下去的星宿老仙丁春秋也投靠了黑木崖。
用户8289326
2022/07/27
6200
网络设备硬核技术内幕 交换机篇 16 辟邪剑法(下)
局域网SDN硬核技术内幕 22 亢龙有悔——规格与限制(下)
数据中心中,随着大规模虚拟化和容器化,在最坏的情况下,TOR交换机理论上有可能需要学习全网VM的MAC或FIB表项。因此,如果一个POD内服务器数量较多,MAC或FIB表项有可能成为规格的瓶颈,需要通过合理规划租户虚拟机所在的物理位置,来避免出现超规格的现象。
用户8289326
2022/07/22
4040
局域网SDN硬核技术内幕 22 亢龙有悔——规格与限制(下)
全网内容最全,质量最高的MPLS及MPLS VPN技术详解,瑞哥力荐!
IP路由其实已经有不短的历史了,在IP发展的过程中,曾经出现过许多的争论,例如路由和交换速度之争,路由和标签交换的地位之争等等。早先的通过软件实现的路由是“很慢的”,是“耗时、耗设备资源的”,加之查表的机制、相关数据字段的重写使得其速度更加缓慢,而对于交换技术,由于对数据帧的读取“较浅”,加上本身的机制、通过专用的硬件实现使得其速度有很大程度的提升。
网络技术联盟站
2020/10/05
10.4K2
【网络干货】MPLS BGP VPN技术详解
Site 在介绍 VPN 时经常会提到“Site”, Site(站点)的含义可以从下述几个方面理解: Site 是指相互之间具备 IP 连通性的一组 IP 系统,并且,这组 IP 系统的 IP 连通性不需通过运营商网络实现。
释然IT杂谈
2020/07/16
5.4K0
【网络干货】MPLS BGP VPN技术详解
局域网SDN硬核技术内幕 28 广泛撒网与重点培养 —— 网络可视化 (下)
前几天,我们看到,RoCE提出的无损以太网需求催生了PFC和ECN等以太网流控技术的普及,但光纤劣化、微突发、错误配置以及大象流踩踏老鼠流等现象,令网络丢包、延时增大以及抖动等造成体验劣化的现象防不胜防。
用户8289326
2022/07/27
5660
局域网SDN硬核技术内幕 28 广泛撒网与重点培养 —— 网络可视化 (下)
局域网SDN硬核技术内幕 21 亢龙有悔——规格与限制(中)
园区场景与数据中心场景的区别是,园区场景不会有大规模的虚拟化,而会有大规模的用户漫游。由于园区网绝大多数用户为人员,1万人的园区终端数一般在1.5万到3万之间,因此,园区网络接入的终端数,和前文中提到的10万以上的虚拟机相比,对网络MAC和FIB表项的压力会小得多。
用户8289326
2022/07/22
5630
局域网SDN硬核技术内幕 21 亢龙有悔——规格与限制(中)
大规模SDN云计算数据中心组网的架构设计
作者简介:熊学涛,中国移动通信有限公司研究院,项目经理。主要研究方向为SDN云计算数据中心和SDN广域网。十多年数据中心、广域网工作经验,CCIE。毕业于西安电子科技大学通信工程学院,华南理工大学工程硕士。
SDNLAB
2020/06/04
2.2K0
局域网SDN技术硬核内幕 - 14 三 从物到人——SDN走进园区网络
为了突破CPU主频的物理上限对服务器计算能力演进的限制,在服务器中普遍采用了多核多CPU技术。虚拟化技术则是将多核多CPU能力发挥到极限的手段。
用户8289326
2022/07/22
7740
局域网SDN技术硬核内幕 - 14 三 从物到人——SDN走进园区网络
局域网SDN技术硬核内幕 9 从软件Overlay到硬件Overlay
IRB(Integrated Routing & Bridging)或DAG (Distributed Anycast Gateway),实现全网所有VM的同网段和跨网段转发;
用户8289326
2022/07/22
7540
局域网SDN技术硬核内幕 9 从软件Overlay到硬件Overlay
局域网SDN硬核技术内幕 23 展望未来——RDMA(上)
摩尔定律被硅芯片物理极限限制->多核技术推动虚拟化大规模应用->数据中心网络大规模虚拟机入网;
用户8289326
2022/07/27
6070
局域网SDN硬核技术内幕 23 展望未来——RDMA(上)
SDN实战团分享(二十一):园区网SDN应用分享
感谢有这样的机会,能够在SDN实战群分享我们在园区网中SDN的应用案例。目前在园区网中的SDN部署和应用还处于起步阶段,今天分享的内容一部分来自于我们的实际应用案例,还有一部分来自于我们搭建的demo环境,希望能够起到抛砖引玉的作用,同时如果有哪些不正确或者不准确的地方,还望各位及时指正。 目前我们在园区网的SDN应用,主要是聚焦在三个方面: 一是路径选择,依据一定的判断或者触发条件,通过流表来控制报文转发的路径; 第二是流量管理,一方面是要对园区内的流量进行采集、统计、分析和处理,形成相应的统计分
SDNLAB
2018/04/02
1.6K0
SDN实战团分享(二十一):园区网SDN应用分享
网络工程师做了那么多项目了,骨干网懂多少?骨干网网络规划设计技术图文讲解的够详细了!
进行网络规划之前需要对网络结构有一个清晰的认识,目前的网络结构大都采取一种层次划的组网方式,大体可以分为以下几个部分:
网络技术联盟站
2019/07/23
4K0
园区网&office网络搭建及配置示例
某天helpdesk的小伙伴问我,你们是怎么快速搭建一套office的网络环境的,当我打算给他详细的介绍我们的园区网的时候,他进一步具化了他的需求:不要求像我们大型园区网那么复杂,只要让小型的公司能满足基本的上网需求就可以,最好告诉他具体的配置命令。我用10几分钟在EVE拖出了几台网络设备,给他演示了下思路和命令。
Ponnie
2021/04/29
1.8K0
园区网&office网络搭建及配置示例
局域网SDN硬核技术内幕 20 亢龙有悔——规格与限制(上)
2016年基于EVPN+VXLAN的局域网SDN技术发端以来,在短短的三年来,已经取得了巨大的成功,如果某家网络方案供应商对该方案支持不完善,将会被排挤出主流圈子,而在大型数据中心或园区网络项目中,SDN的需求也逐渐成为必选项。
用户8289326
2022/07/22
4420
局域网SDN硬核技术内幕 20 亢龙有悔——规格与限制(上)
局域网SDN技术硬核内幕 12 云网CP的日常恩爱——硬件VXLAN转发平面
在大家的祝福之下,云和网络经历了红娘撮合(EVPN信令平面)、领证(层次化端口绑定),终于要过上幸福的小日子了——也就是业务转发。
用户8289326
2022/07/27
6620
局域网SDN技术硬核内幕 12 云网CP的日常恩爱——硬件VXLAN转发平面
传统数据中心 VS Spine-Leaf 结构
为了满足现代网络的需求,数据中心网络必须优先考虑最核心的功能,例如强大的网络带宽、高可用性、可扩展性和安全等。
通往ICT之路
2024/04/17
6350
传统数据中心 VS Spine-Leaf 结构
告别框式设备?去堆叠?去STP?新一代云化园区网络有何不同之处…
园区网络正在逐步跨入万物互联的物联网时代,各类智能终端的爆炸式增长和数字经济下的创新应用对园区网络提出更严苛的要求。借鉴云数据中心网络的发展经验,对园区网络进行云化改造是大家一致认同的解决方案。
星融元Asterfusion
2023/03/30
8490
推荐阅读
相关推荐
局域网SDN技术硬核内幕 - 16 三 从物到人 园区用户漫游的EVPN实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档