関数=クラスのメソッドなモジュール (2)


None is None is None: 関数=クラスのメソッドなモジュール
で、モジュールの関数 = クラスのメソッドなモジュールを書きましたが、
メソッドが多くなると関数を書くのが面倒になるので、
execで自動生成します。



import types

class SomeClass(object):
    def spam1(self, x):
        """spam"""
        print(1, x)
        
    def spam2(self, x, y):
        """spamspam"""
        print(2, x, y)
        
    def spam3(self, x, y, z):
        """spamspamspam"""
        print(3, x, y, z)
    
    def _private_func(self):
        print("private!")

_SomeClass = SomeClass()

def getmethparlist(ob):
    "Get strings describing the arguments for the given object"
    argText1 = argText2 = ""
    # bit of a hack for methods - turn it into a function
    # but we drop the "self" param.
    if type(ob)==types.MethodType:
        fob = ob.im_func
        argOffset = 1
    else:
        fob = ob
        argOffset = 0
    # Try and build one for Python defined functions
    if type(fob) in [types.FunctionType, types.LambdaType]:
        try:
            counter = fob.func_code.co_argcount
            items2 = list(fob.func_code.co_varnames[argOffset:counter])
            realArgs = fob.func_code.co_varnames[argOffset:counter]
            defaults = fob.func_defaults or []
            defaults = list(map(lambda name: "=%s" % repr(name), defaults))
            defaults = [""] * (len(realArgs)-len(defaults)) + defaults
            items1 = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
            if fob.func_code.co_flags & 0x4:
                items1.append("*"+fob.func_code.co_varnames[counter])
                items2.append("*"+fob.func_code.co_varnames[counter])
                counter += 1
            if fob.func_code.co_flags & 0x8:
                items1.append("**"+fob.func_code.co_varnames[counter])
                items2.append("**"+fob.func_code.co_varnames[counter])
            argText1 = ", ".join(items1)
            argText1 = "(%s)" % argText1
            argText2 = ", ".join(items2)
            argText2 = "(%s)" % argText2
        except:
            pass
    return argText1, argText2

def _def_module_functions(glo, loc):
    for name in dir(SomeClass):
        if name.startswith("_"): # __init__ などを公開しないため、_private_funcも公開しない
            continue
        
        pl1, pl2 = getmethparlist(getattr(_SomeClass, name))
        method = getattr(_SomeClass, name)
        defstr = "def {name}({pl1}): return _SomeClass.{name}({pl2})"\
                    .format(name=name, pl1=pl1, pl2=pl2)
        exec defstr in glo, loc
        eval(name, glo, loc).__doc__ = getattr(_SomeClass, name).__doc__

_def_module_functions(globals(), locals())


標準ライブラリのturtleのパクリです。