关于eval:如何将(多个)正则表达式解析的函数参数传递给python函数

How to pass (multiple) regex parsed function parameters to a python function

我正在尝试构建一个python类,它解析一个字符串,如果它与一个看起来像函数调用一样,尝试在类上调用该函数,传递任何参数。

例如,"foo"("a",20")这样的字符串会转换为self.foo("a",20")。

这是迄今为止我掌握的代码……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class FooTranslate(object):
    def create_string(self, letter, size):
        return letter*size

    def run_function(self, func_str):
        match = re.match("([\w_]+)\((|[\W\d\w\,]+)\)", func_str)
        if match == None:
            print"Couldn't match a regex!"
            return False
        else:
            func, fargs = match.groups()

        try:
            if fargs =="":
                return self.__getattribute__(func)()
            else:
                return self.__getattribute__(func)(eval(fargs))
        except AttributeError, e:
            print"Invalid function call: %s" % (func)
            return False

此代码适用于基本情况…

1
2
3
4
5
In [1018]: foot = FooTranslate()
In [1019]: foot.run_function("foo()")
Foo!
In [1020]: foot.run_function("bar(2)")
FooFoo

但是,在使用两个参数函数的情况下:

1
2
3
4
5
6
7
8
9
10
In [1021]: foot.run_function("create_string('a', 2)")

in run_function(self, func_str)
     24                 return self.__getattribute__(func)()
     25             else:
---> 26                 return self.__getattribute__(func)(eval(fargs))
     27         except AttributeError, e:
     28             print"Invalid function call: %s" % (func)

TypeError: create_string() takes exactly 3 arguments (2 given)

原因是eval()调用以元组的形式返回fargs,从而创建了_string()。只接受一个参数。知道如何传递变量个数的参数吗?到函数调用?或者有更好的替代方法?


可以使用*运算符将元组分解为函数的独立参数。例如:

1
2
def f(a, b, c):
    print a, b, c

如果我这样称呼f(...)

1
f((1,2,3))

我得到了一个错误:

1
2
3
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: f() takes exactly 3 arguments (1 given)

但如果我这样称呼它:

1
f(*(1,2,3))

我得到:

1
1 2 3

如果函数接受的参数数目可变,则*运算符甚至可以工作。例如,给定以下函数:

1
2
3
4
5
def f2(a, b, *args):
    print a, b,
    for x in args:
        print x,
    print

如果我打电话给f2(*(1,2,3,4,5)),它会打印:

1
1 2 3 4 5