Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store Python function in JSON

Say I have a JSON file as such:

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

This over-simplifies what I want to try and do, but basically I am attempting
to story a python UDF into a JSON file. Is there a way to do this so that when I do:

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

I can access those values and do something like:

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

To get expected output: 20

NOTE: To my understanding JSON doesn't store functions, so maybe I can store it as a string, and then in my python script parse the string into a function? Not too sure.

like image 490
Connor Watson Avatar asked Aug 20 '18 18:08

Connor Watson


3 Answers

Python has a built in module name marshal that can handle this.

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)

And to get it back...

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))
like image 179
eatmeimadanish Avatar answered Sep 25 '22 14:09

eatmeimadanish


If you really need to store a function in an external JSON file, one solution could be to store a lambda function as a value and use the eval function to evaluate it from your script.

But be aware that using eval in your code could be dangerous, please consider the security implications before using it (see this article from realpython.com).

config.json

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

Your Python file (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)

Demo

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
like image 42
smallwat3r Avatar answered Sep 25 '22 14:09

smallwat3r


Something that is worth trying is just saving it as a string.

You can do stuff like

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

This will create object of the function that you can call. Not really sure what you are trying to do but creating a json file like below should give you what you want to do: (I added the 'func' wrapper because I am assuming you will have multiple functions in one 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

hope this helps

like image 45
Ethan Kulla Avatar answered Sep 24 '22 14:09

Ethan Kulla