列表元素存入字典后如何保留类型?

How to retain the type of list elements after stored in a dictionary?

我有一个嵌套字典,其形式如下。

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)

它抛出了这个错误:

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

有什么我可以做的,可以让 dmy = db['obj 1']['foo'] 的输出成为 [0, a, a+b, 2*a, 2*(b+c)],这是一个列表。 我知道我在做什么可能不是正确的方法,但我需要这样的内容。

注意:我已经尝试将列表元素单独转换为字符串,但是在解析时,我无法获得这种指定形式的内容,即 [0, a, a+b, 2*a, 2*(b+c)].

我能找到的最接近的是这个 link

问题是 abc 是您的(尚不存在的)字典的成员。它们不是变量,所以

    {
    '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]
    },

无效。

您可以通过以下方式解决此问题:

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)

这使得变量 abc 存在并可用。

另一种方法可以是

    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]})

def transform(base, transform):
    base.update(transform(**base))
    return base

    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]})

def transform(base, transform):
    base.update(transform(**base))
    return base

您可以用 lambda 函数替换您的列表推导式,并使用 dill (https://pypi.org/project/dill/) 而不是 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)

现在我设法使用eval 解决了它。我使用的代码如下。

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)

输出:

{'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]

它不保留变量名,而是计算它。 如果有人有更清洁、更好或替代的方法来做到这一点,请随时编辑或 post 回答。