Reputation: 415
I have a nested dictionary, which is of following form.
import pickle
db = {'obj 1':
{
'a' : 1, 'b' : 2, 'c' : 3,
'foo': [0, a, a+b, 2*a, 2*(b+c)],
'bar': [c, c+a, c-b, 2*c, 2*a]
},
'obj 2':
{
'a' : 4, 'b' : 5, 'c' : 6,
'foo': [0, a, a+b, 2*a, 2*(b+c), 0, 0],
'bar': [c, c+a, c-b, 2*c, 2*a, 0, 0]
},
}
with open("db.pkl", "wb") as pkl:
pickle.dump(db, pkl)
print(db)
It's throwing this error:
Traceback (most recent call last):
File "dmy.py", line 8, in <module>
'foo': [0, a, a+b, 2*a, 2*(b+c)],
NameError: name 'a' is not defined
Is there anything I can do such that I'll get the output for dmy = db['obj 1']['foo']
to be [0, a, a+b, 2*a, 2*(b+c)]
which is a list.
I understand what I am doing may not be the right approach, but I need the contents together like this.
Note: I already tried converting the list elements individually into strings, but while parsing, I couldn't get the content in this specified form i.e [0, a, a+b, 2*a, 2*(b+c)]
.
Closest I could find was this link Python - is there a way to store an operation(+ - * /) in a list or as a variable?
Upvotes: 0
Views: 70
Reputation: 632
You could replace your list comprehensions with lambda functions and pickle them using dill (https://pypi.org/project/dill/) instead of pickle:
import dill
db = {'obj 1':
{
'a' : 1, 'b' : 2, 'c' : 3,
'foo': lambda a, b, c : [0, a, a+b, 2*a, 2*(b+c)],
'bar': lambda a, b, c : [c, c+a, c-b, 2*c, 2*a]
},
'obj 2':
{
'a' : 4, 'b' : 5, 'c' : 6,
'foo': lambda a, b, c : [0, a, a+b, 2*a, 2*(b+c), 0, 0],
'bar': lambda a, b, c : [c, c+a, c-b, 2*c, 2*a, 0, 0]
},
}
print(db)
pickled_db = dill.dumps(db)
unpickled_db = dill.loads(pickled_db)
print(unpickled_db)
Upvotes: 1
Reputation: 415
For now I managed to solve it usingeval
. Code I used is given below.
import pickle
db = {'obj 1':
{
'a' : 1,
'b' : 2,
'c' : 3,
'foo': ['0', 'a', 'a+b', '2*a', '2*(b+c)'],
'bar': ['c', 'c+a', 'c-b', '2*c', '2*a']
},
'obj 2':
{
'a' : 4,
'b' : 5,
'c' : 6,
'foo': ['0', 'a', 'a+b', '2*a', '2*(b+c)', '0', '0'],
'bar': ['c', 'c+a', 'c-b', '2*c', '2*a', '0', '0']
},
}
with open("db.pkl", "wb") as pkl:
pickle.dump(db, pkl)
print(db)
with open("db.pkl", "rb") as pkl:
db_pkl = pickle.loads(pkl.read())
a = db_pkl['obj 1']['a']
b = db_pkl['obj 1']['b']
c = db_pkl['obj 1']['c']
arr = db_pkl['obj 1']['foo']
arr_foo = []
for i in range(0, len(arr)):
foo = eval(arr[i])
arr_foo.append(foo)
print("\n", arr_foo)
Output:
{'obj 1': {'a': 1, 'b': 2, 'c': 3, 'foo': ['0', 'a', 'a+b', '2*a', '2*(b+c)'], 'bar': ['c', 'c+a', 'c-b', '2*c', '2*a']}, 'obj 2': {'a': 4, 'b': 5, 'c': 6, 'foo': ['0', 'a', 'a+b', '2*a', '2*(b+c)', '0', '0'], 'bar': ['c', 'c+a', 'c-b', '2*c', '2*a', '0', '0']}}
[0, 1, 3, 2, 10]
It doesn't retain the variable names but rather computes it. If anybody have a cleaner, better or alternate way to do this please feel free to edit or post answer.
Upvotes: 0
Reputation: 91119
The problem is that a
, b
and c
are members of your (not-yet existing) dict. They are not variables, so
{
'a' : 1, 'b' : 2, 'c' : 3,
'foo': [0, a, a+b, 2*a, 2*(b+c)],
'bar': [c, c+a, c-b, 2*c, 2*a]
},
doesn't work.
You can solve this problem in the following way:
import pickle
def build_dict(a, b, c, add=None):
if add is None: add = []
return {
'a': a, 'b': b, 'c' : c,
'foo': [0, a, a+b, 2*a, 2*(b+c)] + add,
'bar': [c, c+a, c-b, 2*c, 2*a] + add
}
db = {'obj 1': build_dict(1, 2, 3),
'obj 2': build_dict(4, 5, 6, [0, 0])}
with open("db.pkl", "wb") as pkl:
pickle.dump(db, pkl)
print(db)
This makes the variables a
, b
and c
exist and usable.
Another way to do it could be
transform({'a' : 1, 'b' : 2, 'c' : 3, lambda a, b, c: {'foo': [0, a, a+b, 2*a, 2*(b+c)], 'bar': [c, c+a, c-b, 2*c, 2*a]})
transform({'a' : 4, 'b' : 5, 'c' : 6, lambda a, b, c: {'foo': [0, a, a+b, 2*a, 2*(b+c), 0, 0], 'bar': [c, c+a, c-b, 2*c, 2*a, 0, 0]})
with
def transform(base, transform):
base.update(transform(**base))
return base
or
transform({'a' : 1, 'b' : 2, 'c' : 3, lambda base: {'foo': [0, base['a'], base['a']+base['b'], 2*base['a'], 2*(base['b']+base['c'])], 'bar': [base['c'], base['c']+base['a'], base['c']-base['b']b, 2*base['c'], 2*base['a']]})
transform({'a' : 4, 'b' : 5, 'c' : 6, lambda base: {'foo': 0, base['a'], base['a']+base['b'], 2*base['a'], 2*(base['b']+base['c']), 0, 0], 'bar': [base['c'], base['c']+base['a'], base['c']-base['b']b, 2*base['c'], 2*base['a'], 0, 0]})
with
def transform(base, transform):
base.update(transform(**base))
return base
Upvotes: 1