Python中实现参数类型检查的简单方法


Posted in Python onApril 21, 2015

Python是一门弱类型语言,很多从C/C++转过来的朋友起初不是很适应。比如,在声明一个函数时,不能指定参数的类型。用C做类比,那就是所有参数都是void*类型!void类型强制转换在C++中被广泛地认为是个坏习惯,不到万不得已是不会使用的。

Python自然没有类型强制转换一说了,因为它是动态语言。首先,所有对象都从Object继承而来,其次,它有强大的内省,如果调用某个不存在的方法会有异常抛出。大多数情况,我们都不需要做参数类型栓查,除了一些特殊情况。例如,某个函数接受一个str类型,结果在实际调用时传入的是unicode,测试过程中又没有代码覆盖到,这样问题就比较严重了。解决方法也很简单,借助Python的内省,很容易就能判断出参数的类型。但是每个地方都写检查代码会很累赘,何况它带来的实际价值并不高。一个好的解决方法是使用装饰器。

'''
 >>> NONE, MEDIUM, STRONG = 0, 1, 2
 >>>
 >>> @accepts(int, int, int)
 ... def average(x, y, z):
 ...   return (x + y + z) / 2
 ...
 >>> average(5.5, 10, 15.0)
 TypeWarning: 'average' method accepts (int, int, int), but was given
 (float, int, float)
 15.25
'''
def accepts(*types, **kw):
  """ Function decorator. Checks that inputs given to decorated function
  are of the expected type.

  Parameters:
  types -- The expected types of the inputs to the decorated function.
       Must specify type for each parameter.
  kw  -- Optional specification of 'debug' level (this is the only valid
       keyword argument, no other should be given).
       debug = ( 0 | 1 | 2 )

  """
  if not kw:
    # default level: MEDIUM
    debug = 1
  else:
    debug = kw['debug']
  try:
    def decorator(f):
      def newf(*args):
        if debug == 0:
          return f(*args)
        assert len(args) == len(types)
        argtypes = tuple(map(type, args))
        if argtypes != types:
          msg = info(f.__name__, types, argtypes, 0)
          if debug == 1:
            print >> sys.stderr, 'TypeWarning: ', msg
          elif debug == 2:
            raise TypeError, msg
        return f(*args)
      newf.__name__ = f.__name__
      return newf
    return decorator
  except KeyError, key:
    raise KeyError, key + "is not a valid keyword argument"
  except TypeError, msg:
    raise TypeError, msg

def info(fname, expected, actual, flag):
  """ Convenience function returns nicely formatted error/warning msg. """
  format = lambda types: ', '.join([str(t).split("'")[1] for t in types])
  expected, actual = format(expected), format(actual)
  msg = "'%s' method " % fname \
     + ("accepts", "returns")[flag] + " (%s), but " % expected\
     + ("was given", "result is")[flag] + " (%s)" % actual
  return msg

本质上讲,这也是一种运行时检查,但效果已经不错了。
更多有趣的装饰器的使用,可以参考这篇文章http://wiki.python.org/moin/PythonDecoratorLibrary

Python 相关文章推荐
Python使用reportlab将目录下所有的文本文件打印成pdf的方法
May 20 Python
Python合并字典键值并去除重复元素的实例
Dec 18 Python
python numpy函数中的linspace创建等差数列详解
Oct 13 Python
Python下调用Linux的Shell命令的方法
Jun 12 Python
python统计字母、空格、数字等字符个数的实例
Jun 29 Python
python实时获取外部程序输出结果的方法
Jan 12 Python
基于python实现音乐播放器代码实例
Jul 01 Python
Python unittest如何生成HTMLTestRunner模块
Sep 08 Python
python 用pandas实现数据透视表功能
Dec 21 Python
学会迭代器设计模式,帮你大幅提升python性能
Jan 03 Python
python Django框架快速入门教程(后台管理)
Jul 21 Python
Python中递归以及递归遍历目录详解
Oct 24 Python
python实现的jpg格式图片修复代码
Apr 21 #Python
在Python的Flask框架中使用日期和时间的教程
Apr 21 #Python
在Python的Flask框架下收发电子邮件的教程
Apr 21 #Python
在Python的Flask框架中实现全文搜索功能
Apr 20 #Python
Python的Flask框架中实现分页功能的教程
Apr 20 #Python
在Python的Flask框架中实现单元测试的教程
Apr 20 #Python
Python的Flask框架中实现登录用户的个人资料和头像的教程
Apr 20 #Python
You might like
PHP中单引号与双引号的区别分析
2014/08/19 PHP
如何用PHP来实现一个动态Web服务器
2015/07/29 PHP
Thinkphp3.2.3整合phpqrcode生成带logo的二维码
2016/07/21 PHP
jQuery 性能优化指南(2)
2009/05/21 Javascript
捕获键盘事件(且兼容各浏览器)
2013/07/03 Javascript
javascript间隔刷新的简单实例
2013/11/14 Javascript
javascript面向对象快速入门实例
2015/01/13 Javascript
JavaScript实现快速排序的方法
2015/07/31 Javascript
20分钟成功编写bootstrap响应式页面 就这么简单
2016/05/12 Javascript
JS简单实现点击复制链接的方法
2016/08/03 Javascript
JavaScript将base64图片转换成formData并通过AJAX提交的实现方法
2016/10/24 Javascript
layui实现form表单同时提交数据和文件的代码
2019/10/25 Javascript
JavaScript利用键盘码控制div移动
2020/03/19 Javascript
详解JS预解析原理
2020/06/16 Javascript
python检测是文件还是目录的方法
2015/07/03 Python
Python3 socket同步通信简单示例
2017/06/07 Python
python爬虫获取多页天涯帖子
2018/02/23 Python
python去掉空白行的多种实现代码
2018/03/19 Python
python实现读取大文件并逐行写入另外一个文件
2018/04/19 Python
Python3日期与时间戳转换的几种方法详解
2019/06/04 Python
python 将字符串中的数字相加求和的实现
2019/07/18 Python
对Python3中列表乘以某一个数的示例详解
2019/07/20 Python
python3实现微型的web服务器
2019/09/03 Python
Tensorflow Summary用法学习笔记
2020/01/10 Python
python基于socket函数实现端口扫描
2020/05/28 Python
Django --Xadmin 判断登录者身份实例
2020/07/03 Python
英国最大的在线蜡烛商店:Candles Direct
2019/03/26 全球购物
MAC彩妆澳洲官网:M·A·C AU
2021/01/17 全球购物
高中生自我评价个人范文
2013/11/09 职场文书
运动会广播稿60字
2014/01/15 职场文书
小学生手册家长评语
2014/04/16 职场文书
三方股东合作协议书范本
2014/09/28 职场文书
新郎结婚感言
2015/07/31 职场文书
员工工作心得体会
2019/05/07 职场文书
在Python中如何使用yield
2021/06/07 Python
CSS作用域(样式分割)的使用汇总
2021/11/07 HTML / CSS