如何将函数定义作为字符串传递给 python 脚本

How do I pass function definition to python script as string

我想将函数定义传递给python命令行脚本。做这个的最好方式是什么?我正在使用 python 2. 假设我有这样的脚本:

#myscript.py
x = load_some_data()
my_function = load_function_definition_from_command_line()
print my_function(x)

我想这样称呼它:python myscript.py 'def fun(x): return len(x)'

如何执行 load_function_definition_from_command_line 部分?

我想象一个解决方法:

  1. 从命令行获取字符串函数定义
  2. 将其写入某个临时目录中扩展名为 .py 的文件
  3. 使用此问题的解决方案从文件加载定义:How to import a module given the full path?
  4. 执行
  5. 清理

但我相信一定有更好的方法。

您可以使用eval到运行代码定义一个字符串。像这样:

import sys

x = load_some_data()
function = eval("".join(sys.argv[1:]))
print(function(x))

对于您的具体示例,尽管您可能必须使用类似 lambda x: len(x)

的内容

正如@Jan-Spurny 正确指出的那样:"Never, never, never use eval unless you're absolutely sure there is no other way. And even then you should stop and think again."

在我看来,更好的策略是将数据加载器和执行器转换为一个模块,该模块的方法将函数作为参数并 运行s 所需的代码。最终结果是这样的:

import data_loader_and_executor

def function(x):
    return len(x)

data_loader_and_executor.run(function)

使用函数exec:

import sys

def load_function_definition_from_command_line():
   exec(sys.argv[1])
   return locals()['fun']

当然你必须知道你的函数将如何命名,但这可以通过传递给你的参数第二个参数来完成:

 $ python myscript.py 'def fun(x): return len(x)' fun

然后您的函数将如下所示:

import sys

def load_function_definition_from_command_line():
   exec(sys.argv[1])
   return locals()[sys.argv[2]]

!!请记住,评估用户输入是非常危险的!!

编辑:由于 fun 将是 locals 中定义的唯一对象,您可以只 return [=16] 中的第一个元素=]:

def load_function_definition_from_command_line():
   exec(sys.argv[1])
   return locals()[0]

您可以使用 eval 或 exec 在您当前的命名空间中创建一个函数。

exec "somefunc(x): return x * 2"
somefunc(2) # 2

您的上下文中的示例

python load_function.py "def f(x): return x * 2"

//load_function.py
import sys

exec sys.argv[1]
print f(2)

命令行输出:
4

编辑: 必填,"It is not wise to execute user input like this."

有关如何执行此操作的正确答案的最明显来源是在 timeit python builtin 库中。

它是这样调用的:

$ python -m timeit '"-".join(str(n) for n in range(100))'

你可以在这里找到源代码,它使用 compileexec 从命令行调用代码

https://hg.python.org/cpython/file/2.7/Lib/timeit.py#l143