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

时间:2021-12-13 07:13:28

I want to pass function definition to a python command line script. What is the best way to do this? I am using python 2. Suppose i have a script like this:

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

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

And i want to call it like this: python myscript.py 'def fun(x): return len(x)'

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

How do i perform the load_function_definition_from_command_line part ?

我如何执行load_function_definition_from_command_line部分?

I imagine a workaround:

我想象一个解决方法:

  1. get the string function definition from command line
  2. 从命令行获取字符串函数定义

  3. write it to a file with .py extension in some temp directory
  4. 将它写入某个临时目录中扩展名为.py的文件

  5. load the definition from file using solutions from this question: How to import a module given the full path?
  6. 使用此问题的解决方案从文件加载定义:如何在给定完整路径的情况下导入模块?

  7. execute
  8. cleanup

But I am sure there must be a better way.

但我相信必须有更好的方法。

4 个解决方案

#1


2  

You can use eval to run code defined in a string. Like so:

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

import sys

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

With your specific example though you might have to use something like lambda x: len(x)

使用您的具体示例,您可能必须使用lambda x:len(x)之类的东西

As @Jan-Spurny rightly points out: "Never, never, never use eval unless you're absolutely sure there is no other way. And even then you should stop and think again."

正如@ Jan-Spurny正确地指出的那样:“永远,永远,永远不要使用eval,除非你绝对确定没有别的办法。即便如此,你应该停下来思考一下。”

In my mind the better strategy would be to turn the data loader and executor into a module with a method that takes a function as an argument and runs the desired code. The end result something like this:

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

import data_loader_and_executor

def function(x):
    return len(x)

data_loader_and_executor.run(function)

#2


0  

You can use eval or exec to create a function in your current namespace.

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

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

Example within your context

您的上下文中的示例

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

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

//load_function.py
import sys

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

Command line output:
4

命令行输出:4

Edit: Obligatory, "It is not wise to execute user input like this."

编辑:强制性,“执行这样的用户输入是不明智的。”

#3


0  

Use function exec:

使用函数exec:

import sys

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

Of course you have to know, how your function will be named, but this can be done by passing to your argument second argument:

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

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

And then your function will look like:

然后你的功能将如下所示:

import sys

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

!!Remember though, that evaluating user input is very dangerous!!

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

Edit: Since fun would be the only object defined in locals, you can just return first element in locals():

编辑:由于fun是本地人定义的唯一对象,你可以只返回locals()中的第一个元素:

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

#4


0  

The most obvious source for the correct answer on how to do this is in the timeit python builtin library.

关于如何执行此操作的正确答案的最明显的来源是timeit python内置库。

It is invoked like this:

它被调用如下:

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

and you can find the source code here, which uses compile and exec to invoke the code from the command line

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

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

#1


2  

You can use eval to run code defined in a string. Like so:

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

import sys

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

With your specific example though you might have to use something like lambda x: len(x)

使用您的具体示例,您可能必须使用lambda x:len(x)之类的东西

As @Jan-Spurny rightly points out: "Never, never, never use eval unless you're absolutely sure there is no other way. And even then you should stop and think again."

正如@ Jan-Spurny正确地指出的那样:“永远,永远,永远不要使用eval,除非你绝对确定没有别的办法。即便如此,你应该停下来思考一下。”

In my mind the better strategy would be to turn the data loader and executor into a module with a method that takes a function as an argument and runs the desired code. The end result something like this:

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

import data_loader_and_executor

def function(x):
    return len(x)

data_loader_and_executor.run(function)

#2


0  

You can use eval or exec to create a function in your current namespace.

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

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

Example within your context

您的上下文中的示例

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

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

//load_function.py
import sys

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

Command line output:
4

命令行输出:4

Edit: Obligatory, "It is not wise to execute user input like this."

编辑:强制性,“执行这样的用户输入是不明智的。”

#3


0  

Use function exec:

使用函数exec:

import sys

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

Of course you have to know, how your function will be named, but this can be done by passing to your argument second argument:

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

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

And then your function will look like:

然后你的功能将如下所示:

import sys

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

!!Remember though, that evaluating user input is very dangerous!!

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

Edit: Since fun would be the only object defined in locals, you can just return first element in locals():

编辑:由于fun是本地人定义的唯一对象,你可以只返回locals()中的第一个元素:

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

#4


0  

The most obvious source for the correct answer on how to do this is in the timeit python builtin library.

关于如何执行此操作的正确答案的最明显的来源是timeit python内置库。

It is invoked like this:

它被调用如下:

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

and you can find the source code here, which uses compile and exec to invoke the code from the command line

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

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