【问题标题】:Store Python function in JSON以 JSON 格式存储 Python 函数
【发布时间】:2019-01-26 22:33:31
【问题描述】:

假设我有一个这样的 JSON 文件:

{
  "x":5,
  "y":4,
  "func" : def multiplier(a,b):
               return a*d
}

这过度简化了我想要尝试和做的事情,但基本上我正在尝试
将 python UDF 写入 JSON 文件。有没有办法做到这一点,这样当我 做:

with open('config.json') as f:
    data = json.load(f)

我可以访问这些值并执行以下操作:

v1, v2 = data['x'], data['y']
mult = data['func']
print(mult(v1,v2))

要获得预期的输出:20

注意:据我了解,JSON 不存储函数,所以也许我可以将其存储为字符串,然后在我的 python 脚本中将字符串解析为函数?不太确定。

【问题讨论】:

  • 不是一个 JSON 文件。它也不是有效的 Python 字典语法。
  • 你觉得在 .py 文件中编写函数并导入它的感觉如何?
  • @jonrsharpe 减去函数定义,我的 JSON 文件的其他一切似乎都很好。我试图问一种解决这个问题的方法,这就是为什么我建议将函数定义用引号括起来以尝试使用 python 将其解析为有效函数。
  • 如果您正在考虑将 XML 存储在 Python 无法执行的文件格式中,并且可以使用您选择的任何语言进行访问,我建议您使用 XML。
  • 当然,在 json 中仅存储模块和函数名称在技术上是可行的...import_module 可以导入给定名称的模块,您可以使用getattr 获取给定名称的函数.但很难说这对于您想要实现的目标是否是最实用的方法。

标签: python json user-defined-functions


【解决方案1】:

Python 有一个内置的模块名称marshal 可以处理这个问题。

import marshal, ujson as json

def multiplier(a, b):
    return a * b

x = {
  "x":5,
  "y":4,
  "func" : marshal.dumps(multiplier.func_code)
}

x = json.dumps(x)
print(x)

然后把它拿回来......

x = json.loads(x)
x = marshal.loads(x['func'])
# maybe save the function name in dict
func = types.FunctionType(x, globals(), "some_func_name") 

print(func(2,4))

【讨论】:

  • 嗯,元帅看起来很有帮助。首先转储然后将其取回似乎是一个额外的步骤,特别是考虑到我想从 JSON 而不是从 python 脚本开始,但我会看看我是否也可以实现这一点。谢谢!
  • 我包含 JSON 是因为那是您想要的格式?您如何建议在不转换为 python 对象的情况下轻松转换元帅?
【解决方案2】:

如果您确实需要将函数存储在外部 JSON 文件中,一种解决方案可能是将 lambda 函数存储为一个值,并使用 eval 函数从您的脚本中对其进行评估。

但请注意,在您的代码中使用 eval 可能很危险,请在使用前考虑安全隐患(请参阅 realpython.com 中的 this 文章)。

config.json

{
  "x": 5,
  "y": 4,
  "function": "lambda x, y : x * y"
}

您的 Python 文件 (test.py)

import json


def run():
    """Run function from JSON config."""

    with open("config.json") as f:
        data = json.load(f)

    x, y = data["x"], data["y"]
    multiplier = eval(data["function"])
    return multiplier(x, y)


if __name__ == "__main__":
   result = run()
   print(result)

演示

In[2]: ls
test.py
config.json

In[3]: import json

In[4]: def run():
  ...:     """Run function from JSON config."""
  ...: 
  ...:     with open("config.json") as f:
  ...:         data = json.load(f)
  ...: 
  ...:     x, y = data["x"], data["y"]
  ...:     multiplier = eval(data["func"])
  ...:     return(multiplier(x, y))
  ...:    

In[5]: run()
20

【讨论】:

  • 这很有帮助,谢谢! lambas 是一个不错的选择,我需要让我超级习惯写作,因为它们可以减少 UDF 的冗长。我还将测试这种方法,看看我的解决方案有多复杂。再次感谢您!
【解决方案3】:

值得尝试的是将其保存为字符串。

你可以做类似的事情

my_func = "
def function(a,b):
   constant = {input_var}
   return a*b + constant
"
my_func.format(input_var = 5)

exec(my_func)
function(1,2) # will return 7

这将创建您可以调用的函数的对象。不太确定您要做什么,但创建如下所示的 json 文件应该可以满足您的需求: (我添加了 'func' 包装器,因为我假设您将在一个 JSON 中拥有多个函数)

function_json = {
'func': {
    'x':5
    'y':4
    'multiplier':
'def multiplier(a,b):
    return a*b'
}

x=function_json['func']['x']
y=function_json['func']['y']
exec(function_json['func']['multiplier'])
multiplier(x,y) # will return 20

希望对你有帮助

【讨论】:

  • 这很有帮助,谢谢!我不知道'exec',但我尝试过它并且它有效。我必须做一些测试,看看我能用这种方法有多复杂
  • 我会小心 eval...它可能非常危险...但我想这也可以。
  • Exec 和 eval 确实有问题,但是 exec() 优于 eval() 的好处是它可以像函数一样获取整个代码块并执行它。对于这个应用程序,我发现 exec() 比 eval() 效果更好。
【解决方案4】:

我已经尝试并结合了ethan-kullaeatmeimadanish 的解决方案

以下代码有效:

my_func = '''
def function(a,b):
   constant = {input_var}
   return a*b + constant
'''

exec(my_func.format(input_var=5), globals())
# For Python 3.x, use globals() to change global context
function(2,2)

【讨论】:

    猜你喜欢
    • 2021-08-07
    • 2012-04-15
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多