Python 杂记之 根据版本号自动调用泛函数
作者: Jim Wang 公众号: 巴博萨船长
在未来使用中,窗口的表现形式可能根据版本的不同而不同,但又需要同时要保证代码的向下兼容,也就说可以不断地添加了新的窗口,那老用户的老版本也应该能够继续使用。所以要根据版本信息进行代码(至少是窗体生成部分的代码)的调度。
调度方式1, 传统设计理念中,也就是预定义一部分类方法,在根据实际需求,用字典索引的方式查找类方法或者函数。如下,
可以如下方式进行调度:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def p1(args):
whatever
def p2(more args):
whatever
myDict = {
"P1": p1,
"P2": p2,
...
"Pn": pn
}
def myMain(name):
myDict[name]()或者以下列方式进行调度:
1
2
3
4
5
6
7
8
9
10def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
def ExecPn():
pass
locals()['Exec' + key]()两种的调度思路是一致的。
调度方式2, Python标准库种有一个functools模块,该模块可以为可调用对象定义高阶函数和操作。即,依据现有函数定义新的函数。我们实现的方式运用了partial函数和singledispatch函数,parital由于定义偏函数,也就是为了固定函数或者方法的一个参数,在该实现方式种用于向Event的Handler传递第二个参数。singledispatch是用于函数调度,即将函数装饰为泛函数。其根据参数的数据类型实现函数的自主调度。因为我们要实现类方法根据不同的版本进行自主调度,就意味着需要将版本作为一种新的数据类型。
- 基本代码如下:
1 | import wx |
在日常实践种singledispatch都是用来调度函数的,如果直接用在类方法上,会出现输入参数异常的问题。在这里我们就需要重新定义singledispatch进而得到一个methdispatch的函数。因为类方法的第一个参数为self即实例,所以我们要在函数种dispatch()第二个个参数。检查其数据类型然后调度注册的函数。
1 | def methdispatch(func): |
为了实现类方法依照版本类型自主调度,上文中说到,我们要将版本注册成新的数据类型,或者类。在未来任何需要新的版本,都要将该版本好吧注册成新的类,代码如下:
1 | thisModule = modules[__name__] |
普通的类方法可以用如下的代码实现调度,如果采用上述的方式进行版本数据类型的声明,一些IDE并不能够自动找到新注册的数据类型,就会出现该类型未找到的错,如果使用Eclipse就需要添加特别注释@UndefinedVariable:
1 | # @UndefinedVariable |
针对一些特别的类方法如,事件处理函数,就要用到partial函数,代码如下。需要注意的是在这里partial固定的是类方法OnButtonClicked的第一个参数,第二个参数是Event。 理解了这些,我们就可以根据版本的不同调度同一事件的不同时间的处理方法了。
1 | self.btn.Bind(wx.EVT_BUTTON, partial(self.OnButtonClicked, self.objVersion)) |
注册同一事件处理函数的泛函数方法如下,泛函数的名称可以自由定义,但是_在这里确实是一个很好的选择,如果某一版本的泛函数没被注册,就会使用函数的本体:
1 |
|
上述的内容都是在一个Python种的使用情况,下面我们介绍一下如何跨模块实现上述内容,在跨模块使用该调度方式的时候,需要注意要从基本模块加载版本的数据类型,在注册泛函数的时候写法也于在同一模块种的不同,本例种:@ClassDialog.CreateWidgets.register(v1_60),从类名,类方法名再进而注册版本类型。
1 | import wx |
上述就是使用functools种的两个函数实现依据不同版本调度不同的泛函数的全部内容
文章首发于 Jim Wang's blog , 转载文章请务必以超链接形式标明文章出处,作者信息及本版权声明。