前言

  最近开始开发 QtLib 库,将一些 Qt 的黑科技功能进一步集成到一起。
  在这个过程中会遇到某些复杂的函数,当中需要大量的可选参数,而且很多参数是不同模式下才需要的。
  由于 Python 没有 C++ 那种对函数重载的功能,如果写多个同名函数,会覆盖掉前面的函数。
  因此我只好在参数上做判断进行过滤。
  那么怎样才能快速判断传入的参数是否合法,如果全部都要写判断就太浪费时间了。
  自己开发一个参数验证库也觉得的很麻烦,总觉得应该有人也遇到和我一样的问题,因此我开始网上搜索现成的库。

系列文章推荐

  后来在简书上搜到了非常棒的系列文章,介绍了三个不同的参数验证库。

  前面两个库比较小巧,功能相对简陋,但是可用。
  第三个的 voluptuous 是非常成熟的库了,在github上有上千颗星,非常推荐。

  我看完了三篇文章之后可以看到三个库都有大量的功能是重合的,而 voluptuous 在使用上更胜一筹。
  上面的文章有很详细的使用方法介绍,我感觉也非常受用。

voluptuous 使用介绍

  其实上面的文章也有很详细的使用说明。
  我简单说用代码的形式罗列有用的点。

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
from voluptuous import Schema
schema = Schema({
'text': str,
'active': bool,
'index': int,
})

data = {
'text': 1,
'active': True,
'index': 1,
}

data = schema(data)

Traceback (most recent call last):
File "c:/Users/Administrator/Desktop/hexo/source/_posts/Python/officail_explore/test.py", line 14, in <module>
data = schema(data)
File "D:\Program Files\Autodesk\Maya2017\Python\lib\site-packages\voluptuous\schema_builder.py", line 267, in __call__
return self._compiled([], data)
File "D:\Program Files\Autodesk\Maya2017\Python\lib\site-packages\voluptuous\schema_builder.py", line 589, in validate_dict
return base_validate(path, iteritems(data), out)
File "D:\Program Files\Autodesk\Maya2017\Python\lib\site-packages\voluptuous\schema_builder.py", line 427, in validate_mapping
raise er.MultipleInvalid(errors)
voluptuous.error.MultipleInvalid: expected str for dictionary value @ data['text']

  通过定义数据类型,可以将传参进行判断。
  参数传递不正确就会报错提醒

1
2
3
4
5
6
7
8
9
from voluptuous import Required, All, Length, Range
schema = Schema({
# NOTE 限定必传参数,并且字符串长度是1
Required('q'): All(str, Length(min=1)),
# NOTE 限定必传参数,默认值为5,数字在 1-20 之间
Required('per_page', default=5): All(int, Range(min=1, max=20)),
# NOTE 数字表小于0
'page': All(int, Range(min=0)),
})

  更多用法还是参考上面的文章介绍。

singledispatch 原生库

  后来再研究 dayu_widget UI库 的时候发现里面使用了 singledispatch 库
  查了一下原来 singledispatch 在 Python3 的官方包 functools 里面引入了。
  可以通过这个库来实现类似上面说的C++函数重载的效果,也就是传入不同的参数函数调用不同。


  由于是 python3 才有的新特性,如果要在 Python2 中使用需要使用第三方做好的兼容库来实现。 pypi地址

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
from singledispatch import singledispatch
@singledispatch
def fun(arg, verbose=False):
if verbose:
print("generic usage")
print(arg)

@fun.register(int)
def _(arg, verbose=False):
if verbose:
print("int usage")
print(arg)

@fun.register(list)
def _(arg, verbose=False):
if verbose:
print("list usage")
for i, elem in enumerate(arg):
print(i, elem)

fun("1",True)
fun(1,True)
fun([1],True)

# generic usage
# 1
# int usage
# 1
# list usage
# (0, 1)

  也可以将已有的函数注册为特定函数的重载函数。

1
2
3
4
def nothing(arg, verbose=False):
print("Nothing.")
fun.register(type(None), nothing)
fun(None,True)

  也可以通过 dispatch 方法获取特定调用的函数

1
2
3
4
# 获取上面定义的 list 传参方法
fun.dispatch(list)
# 甚至可以传入错误参数进行调用_(:з」∠)_(这就没有办法检测参数是否合法了)
fun.dispatch(int)("5",True)

总结

  上面就是我最近接触到用来简化参数调用的方法。
  singledispatch 可以很方便将函数拆解成不同类型调用,把一个复杂函数的功能分割出来。
  voluptuous 则是用于快速验证传入参数是否是预想的类型。
  两者结合对于复杂程序开发非常方便。


  有时间的话要研究一下 singledispatch 这种黑科技是怎么在 Python2 中实现的。