资讯专栏INFORMATION COLUMN

利用装饰器给python的函数加上类型限制

BigTomato / 2951人阅读

摘要:列表越界的列表类似于动态数组,没有长度的限制。比如对将要传进内层函数的参数进行检测等,从而实现对参数的类型进行限制。对二维列表的每一维列表进行长度限制,不足指定长度,自动补充指定元素。

前言

作为一名python的脑残粉,请先跟我念一遍python大法好。

其作为动态语言的灵活,简介的代码,确实在某些情况下确实比其他编程语言要好。但你有没有想过,有时这些灵活的语法,可能会造成一些糟糕的体验。尤其是针对新手,python易上手不假,但动态语言写得项目规模一大,其实比相对严谨的静态语言,更考验程序员的内力。

哪怕你只是用过python写过一些初等的项目,那你可能也体验过以下这种情况。

莫名其妙的传错参数类型。
python不需要显式声明参数类型,同样,什么样的变量都可以往函数里扔,包括函数(python支持函数式编程),这容易出现一个问题,如果一个函数不是自己设计的,你很可能网里面传了错误类型的参数。当然,这样大多数触发异常,因为传错类型意味着函数的一些操作该类型不支持。但有时传了错误的参数类型,却并不会触发异常(比如字符串相加和数字相加,以及一切对象的==判断),不会触发异常结果却是错误的,这就意味着出现了问题更难确定位置,甚至如果这个函数的返回值,再传进其他函数(假设叫B)时,当你发现得到结果错误时,你很可能以为是B函数的逻辑设计出现了错误,从而花费大量的时间在错误的地方,使用python多数是对开发效率比较重要的场景,而很可能因为一个粗心,使得写代码的时间短了,结果将时间都花在找BUG上了。

进行操作之前忘记了转型
典型的就是把参数类型为strint相加。或者把str传进range()里面。

列表越界
python的列表类似于动态数组,没有长度的限制。虽然大多数我们只需用for x in one_list即可完成对列表的访问,而不需要去考虑列表的长度。但其实还有一种情景,比如说一个列表(或者元组)中元素的次序是有意义的,比如说[name,age,sex]而且这可能是某个函数动态生成的,比如爬虫爬取网站后从里面挑选信息后返回,这时,如果这个网站中age,sex的信息缺失,python可不会自动补充None下去,至少我没看见有人的函数或方法会考虑到这一点,而是直接给你返回[name],而如果你需要获取age,而直接访问下标为1的元素,则会触发异常。

类似的还有种种,当然并非不可解决,比如足够多的assertisinstance,足够严谨的逻辑设计,枯燥但很有必要的单元测试等等……但使用python很多时候就是为了加快开发效率,上面的这些措施显然太过麻烦。

断断续续的写了一两天,弄了几个装饰器来解决这些问题,下面开始分享一下。

什么是装饰器

需要了解pythopn中装饰器的基本概念,可以参考一下廖老师的py教程
点这里

如何利用装饰器限制函数的参数和返回值

使用装饰器可以使得一个函数外面加上某些操作然后在重新返回到你定义的函数名字指定的对象上。

说实话,我很难用言语描述出这种关系,直接上代码好了。

以使用装饰器限制函数参数类型为例:

装饰器的实现如下:

def type_limit(*typeLimit,**returnType):
    def test_value_type(func):
        def wrapper(*param,**kw):
            length = len(typeLimit)
            if length != len(param):
                raise LimitError("The list of typeLimit and param must have the same length")
            for index in range(length):
                t = typeLimit[index]
                p = param[index]
                if not isinstance(p,t):
                    raise LimitError("The param %s should be %s,but it"s %s now!"%(str(p),type(t()),type(p)))  
            res = func(*param,**kw)
            if "returnType" in returnType:
                limit = returnType["returnType"]
                if  not isinstance(res,limit):
                    raise LimitError("This function must return a value that is %s,but now it"s %s"%(limit,type(res) ) )
            return res
        return wrapper
    return test_value_type

假设我希望实现一个函数,实现两数求和,为了避免传进去的是两个字符串,造成字符串连接,我需要限制其类型都为int

这时,我们可以这么做:

@type_limit(int,int)
def test(x,y):
    return x+y
    

这个定义的过程发生了什么呢?上述代码等价于

temp = type_limit(int,int) #temp =  test_value_type
test = temp(test) #这是,test已经在原test上经过修饰,指向wrapper

而在wrapper中,最终会返回调用原test的结果,这个装饰器做的,只不过是在调用原test前,利用
isinstance进行了一遍类型检测而已。这样,我们可以简单的模仿像javaC++这样的静态语言一样,在声明的时候就对参数类型进行限制了。

理解这个装饰器把握着一下几点:

函数可以作为变量使用,即可以作为参数和返回值

装饰器利用了函数内的函数,可以访问外层函数之间的一些变量从而对内层函数进行修饰。(比如对将要传进内层函数的参数进行检测等),从而实现对参数的类型进行限制。

理解这两点后,你可以自由的修改和拓展这些装饰器,如果你有更好的实现,记得在githubpull给我哦,github地址稍后给出。

其他相关的限制

除上述外,我还是实现了其他限制:

列表长度的限制,不足指定长度,自动补充指定元素。

对二维列表的每一维列表进行长度限制,不足指定长度,自动补充指定元素。主要为某些算法进行限制。

常量类Const,目测没有什么用

对列表的每一元素的类型进行限制

后记

限于篇幅,其他的代码不一一在这里介绍,关键思路在上文已给出,其余代码开源在github上,如果需要,你可以直接拿去使用。不过记得不要滥用。

github地址

如有更好的建议和或不正确的地方,可以在本文或github下告知。

如有错别字……请忽略(^ ^)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45429.html

相关文章

  • JS 装饰器,一篇就够

    摘要:的装饰器中的同样借鉴了这个语法糖,不过依赖于的方法。等同于也就是说,装饰器是一个对类进行处理的函数。别名或装饰器在控制台显示一条警告,表示该方法将废除。有了装饰器,就可以改写上面的代码。 更多文章,请在Github blog查看 在 ES6 中增加了对类对象的相关定义和操作(比如 class 和 extends ),这就使得我们在多个不同类之间共享或者扩展一些方法或者行为的时候,变得并...

    learning 评论0 收藏0
  • Python - @property 方法变属性

    摘要:属性有三个装饰器。当属性只有方法,则为只有只读属性。使用规则只读属性只有方法,在方法前加上可读可写属性有和方法,在方法上使用属性名。 @property @property是内置的装饰器,与普通装饰器原理是一样的,只不过返回的不是函数,而是类对象. @property负责把一个方法变成属性进行调用,保证对参数进行必要的检查。 属性有三个装饰器:setter、getter、dele...

    Alliot 评论0 收藏0
  • Python学习之路8.2-对Python补充

    摘要:本章主要是对上一章类的补充。对于多态的补充子类可以被看成是父类的类型,但父类不能被看成是子类的类型。仍然以类为例,动物里有哺乳动物,卵生动物,有能飞的动物和不能飞的动物,这是两种大的分类方式。一般在中,以为结尾类的都作为接口。 《Python编程:从入门到实践》笔记。本章主要是对上一章Python类的补充。 1. 从一个类派生出所有类 上一篇文章说道Python类的定义与继承一般是如下...

    liukai90 评论0 收藏0
  • Python技术点

    摘要:内置函数实现对可迭代对象进行进一步处理。文件文件的打开权限打开文件,文件不存在报异常写入文件,文件不存在则创建。文件不存在则创建。追加文件,具有读写权限。 Python基础类型: 1.Tuple元组,内容不可改变,但是允许元素内部存在list等类型的元素,并且允许改变列表的值,所谓内容不可变指的是在内存中指向的地址是不变的。 temp=(1,2,[3,4]) temp[-1]....

    Lionad-Morotar 评论0 收藏0
  • Python: 会打扮装饰

    摘要:一般情况下,我们使用装饰器提供的语法糖,来简化上面的写法像上面的情况,可以动态修改函数或类功能的函数就是装饰器。本文标题为会打扮的装饰器本文链接为参考资料修饰器的函数式编程中的装饰器介绍思诚之道装饰器入门与提高赖明星 装饰器 我们知道,在 Python 中,我们可以像使用变量一样使用函数: 函数可以被赋值给其他变量 函数可以被删除 可以在函数里面再定义函数 函数可以作为参数传递给另外...

    blastz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<