python:带有字符串输入的分派方法

python:带有字符串输入的分派方法,python,Python,我需要编写一个包含3个参数的方法: 带有函数名的字符串 该函数参数的有序列表。这包括具有默认值的参数和*varargs,但不包括**kwargs 表示任何附加关键字参数的dict,或None如果没有 我需要使用这个输入来检索一个函数并调用它。例如: def dispatch(name, args, kwargs=None): do_magic_here(name, args, kwargs) def meth1(): print "meth1" def meth2(a, b)

我需要编写一个包含3个参数的方法:

  • 带有函数名的
    字符串
  • 该函数参数的有序
    列表。这包括具有默认值的参数和
    *varargs
    ,但不包括
    **kwargs
  • 表示任何附加关键字参数的
    dict
    ,或
    None
    如果没有
  • 我需要使用这个输入来检索一个函数并调用它。例如:

    def dispatch(name, args, kwargs=None):
        do_magic_here(name, args, kwargs)
    
    def meth1():
        print "meth1"
    
    def meth2(a, b):
        print "meth2: %s %s" % (a, b)
    
    def meth3(a, **kwargs):
        print "meth3: " + a
        for k,v in kwargs.iteritems():
            print "%s: %s" % (k,v)
    
    def dispatch(name, *args, **kwargs):
      globals()[name](*args, **kwargs)
    
    dispatch('meth3', 'hello', foo='bar')
    # meth3: hello
    # foo: bar
    
    我需要能够这样称呼:

    >>> dispatch("meth1", [])
    meth1
    >>> dispatch("meth2", [1, 3])
    meth2: 1 3
    >>> dispatch("meth3", [1], {"hello":2, "there":3})
    meth3: 1
    hello: 2
    there: 3
    
    我可以这样做:

    def do_magic_here(name, args, kwargs=None):
        if name=="meth1":
            meth1()
        if name=="meth2":
            meth2(args[0], args[1])
        if name=="meth3":
            meth3(args[0], **kwargs)
    

    但我正在尝试调度大约40个方法,而且这个数字可能会扩大,所以我希望有一种更编程的方法来实现这一点。我正在用
    getattr
    查看一些东西,但我不能完全弄清楚。

    事实上,
    getattr
    会帮你达到目的

    class X:
        def a(self):
            print('a called')
        def b(self, arg):
            print('b called with ' + arg)
    
    x = X()
    getattr(x, 'a')()
    # a called
    getattr(x, 'b')('foo')
    # b called with foo
    
    就像
    getattr
    以相同的方式处理方法和字段一样,您可以处理 通过引用
    locals()
    globals()
    与类不关联的函数和变量

    如果要引用全局范围中的函数:

    globals()['meth'](args)
    
    例如:

    def dispatch(name, args, kwargs=None):
        do_magic_here(name, args, kwargs)
    
    def meth1():
        print "meth1"
    
    def meth2(a, b):
        print "meth2: %s %s" % (a, b)
    
    def meth3(a, **kwargs):
        print "meth3: " + a
        for k,v in kwargs.iteritems():
            print "%s: %s" % (k,v)
    
    def dispatch(name, *args, **kwargs):
      globals()[name](*args, **kwargs)
    
    dispatch('meth3', 'hello', foo='bar')
    # meth3: hello
    # foo: bar
    
    请记住,在Python中,始终可以使用
    **
    传递参数列表或关键字参数dict:

    dispatch('meth3', *['hello'], **{'foo':'bar'})
    
    如果您确实喜欢将参数作为list/dict传递给
    dispatch

    def dispatch(name, args, kwargs):
      globals()[name](*args, **kwargs)
    
    dispatch('meth3', ['hello'], {'foo': 'bar'})
    
    我会用

    def dispatch(name, *args, **kwargs):
        func_name_dict[name](*args, **kwargs)
    

    允许您更自然、更透明地传递
    args
    kwargs

    >>> dispatch("meth2", 1, 3)
    meth2: 1 3
    

    当然,您可以使用
    globals()
    locals()
    来代替dict,但是您可能需要注意每个命名空间中哪些函数是您愿意或不愿意向调用方公开的

    如果这些方法不在类中怎么办?那么它们不是方法而是函数。我将更新答案。值得注意的是,
    dispatch
    不接受
    *args
    **kwargs
    ,而是实际的列表和字典。这有区别吗?它必须这样定义,因为我工作的框架,如果你真的不需要传递列表和指令,我会这样做;这是在Python中传递未知参数(例如装饰符、方法重写)的更自然的方式@ewok您仍然可以通过
    *
    解压列表,通过
    **
    解压dicts。也许你应该把
    kwargs
    的默认值改为
    {}
    @ewok,只是为了详细说明schwobaseggl的观点,你现在可以使用
    dispatch(*args,**kwargs)
    @HumphreyTriscuit,我想他的意思是如果他说
    [1],{a':2}
    这些将被解释为args,其中第一个arg是
    列表
    ,第二个是
    dict
    。为了避免这种情况,您可以执行类似于
    dispatch=lambda name,args,kwargs:func\u name\u dict[name](*args,**kwargs)