Rokiのチラ裏

学生による学習のログ

python de 同一メゾッド名の型チェック付き呼び分け

バイト中、以下のようなコードを見つけた。

def something1(x,y):
    print 'something1'
def something2(x,y):
    print 'something2'
def something3(x,y,z):
    print 'something3'

def invoke(*args):
    argc=len(args)
    exp_message='not match function'

    if argc==3:
        something3(args[0],args[1],args[2])
    elif argc==2:
        if isinstance(args[0],int) and isinstance(args[1],str):
            something2(args[0],args[1])
        elif isinstance(args[0],int) and  isinstance(args[1],float):
            something1(args[0],args[1])
        else:
            raise Exception,exp_message
    else:
        raise Exception,exp_message

invoke("hoge",42,4.2)
invoke(42,"hoge")
invoke(42,4.2)

うーん。凄まじいハードコードである。やりたい事はオーバーロードだろう。私はpythonの専門家ではないので、更に良い解決法はあるのだろうが、取り敢えず以下のように引数の違いで呼び分ける上で型チェックをするようにした。

import sys

exp_message="not match function"

class Invoker(object):
    def __init__(self):
        self.functions=[]

    def __call__(self,*args,**kwargs):
        for function in self.functions:
            if len(args)==function.func_code.co_argcount:
                return function(*args)
        raise Exception,exp_message

def invoke_impl(func):
    hs=sys._getframe(1).f_globals.get(func.__name__)
    if hs is None:
        hs=Invoker()
    hs.functions.append(func)

    return hs;

@invoke_impl
def something(x,y,z):
    if not (isinstance(x,str) and isinstance(y,int) and isinstance(z,float)):
        raise Exception,exp_message
    print 'something3'

@invoke_impl
def something(x,y):
    if isinstance(x,int) and isinstance(y,str):
        print 'something2'
    elif isinstance(x,int) and isinstance(y,float):
        print 'something1'
    else:
        raise Exception,exp_message

something("hoge",42,4.2)
something(42,"hoge")
something(42,4.2)

型チェックはやはりisinstanceを使う他はないだろうか。