设置:我从一个非正方形的二维值列表开始:
list = [ ['A','B','C'], np.array([1, 2, 3, 4]), np.array([0.5, 1.5]) ]
然后将此列表写入文件。稍后,我需要从文件中提取相同的列表以进行处理。
当前方法:我以一种非常简单的方式处理书写:str()
和f.write()
命令。部分原因是它易于设置;部分原因是因为同一文件包含正在写入的其他非列表对象(字符串,字典,整数等)。但是,当我加载文件时,另一端却遇到麻烦。最直接的方法是
loadList = list(stringFromFile)
print(loadList)
> [ "[" "[" "'" "A" "'" "," "'" "B" "'" ...
,依此类推。显然,这不是我想要的。添加分离器会更好一点:
loadList = list(stringFromFile.split(','))
print(loadList)
> [ "[['A'" , "'B'" , "'C']" , "np.array([1", "2", "3", "4])", "np.array([0.5", "1.5"])]" ]
...但未正确处理细分。重新定义分隔符(...split('],')
)对array()元素的处理不正确,依此类推。
沿着这条路径,我可以看到一种使其与大量if
渔获物,经过精心改良的分离器以及一些特殊情况一起使用的方法。但是,以这种方式执行此操作感觉很笨拙。我还怀疑它是否可以推广到用户可能扔给它的任何奇怪构造的二维列表。
是否有更优雅的方法来实现这一目标?我愿意更改我的写方法和/或读方法,但是如果不对整个程序进行一些相当大的重新设计,就无法更改列表对象本身的处理。
答案 0 :(得分:2)
据我所知,问题在于您正在超负荷保存数据的目的。您正在创建自己的数据存储格式;您希望它是人类可读的,但同时您也希望它易于兼容,以读回各种Python数据结构。如果您坚持将无限制的数据混合在一个容器(一个文本文件)中,那么您将遇到麻烦。
我不会陷入信息理论的冲突;这简直是在问太多简单的文字。各种模块都有自己的写入和读取数据的方法。有关此类示例,请参见numpy.savetxt
。 Python有一些附加模块来处理内置类型,您可以通过适当的搜索找到它们。 JSON可以很好地用作结构化数据的通用载体。
通常的治疗方法是以下两种可能性之一:
eval
函数以补偿您之前的数据。这种方式非常脆弱。答案 1 :(得分:1)
使用str
写出列表将使事情变得困难。 str
旨在产生人类可读的字符串,该字符串可能不适合机器解析。
通常,这是序列化的示例,使用处理两个“方向”(将对象序列化为文件,并从文件内容反序列化)的库可能最容易)给你。
您可以使用多种方法。从Python标准库中可以很容易地使用以下两种方法:Pickle或JSON。
>>> import numpy
>>> import pickle
>>> l = [ ['A','B','C'], numpy.array([1, 2, 3, 4]), numpy.array([0.5, 1.5]) ]
>>> l
[['A', 'B', 'C'], array([1, 2, 3, 4]), array([0.5, 1.5])]
>>>
>>> # Save the list to a file.
>>> with open('data.pkl', 'wb') as f:
... pickle.dump(l, f)
...
>>> # Load the list from a file.
>>> with open('data.pkl', 'rb') as f:
... l_copy = pickle.load(f)
...
>>> l_copy
[['A', 'B', 'C'], array([1, 2, 3, 4]), array([0.5, 1.5])]
JSON的主要警告是,在加载数据时,将没有一种简单的方法来将某些元素作为 numpy数组加载,而将其他元素作为 Python列表 。换句话说,天真的JSON序列化不会保留类型之间的区别。参见NumPy array is not JSON serializable
>>> import numpy
>>> import json
>>>
>>> l = [ ['A','B','C'], numpy.array([1, 2, 3, 4]), numpy.array([0.5, 1.5]) ]
>>> def serialize_as_json(nested_list, filename):
... # Need to convert numpy array to Python list of Python ints/floats.
... l = [(elem.tolist() if isinstance(elem, numpy.ndarray) else elem) for elem in nested_list]
... with open(filename, 'w') as f:
... json.dump(l, f)
...
>>> serialize_as_json(l, 'data.json')
>>>
>>> l_copy = json.load(open('data.json'))
>>> # Note that l_copy contains lists, not numpy arrays.
>>> l_copy
[['A', 'B', 'C'], [1, 2, 3, 4], [0.5, 1.5]]
答案 2 :(得分:0)
假设您的文件是一个文档,其行为就像一个简单的.txt,并且您感兴趣的列表位于上述文档的第一行(也是第一行),那么您要做的是以下:
import numpy as np
L = eval(open('list.txt').readlines()[0])
其中'list.txt'
是您的文件,而L
是脚本存储列表的变量。这不是最好的方法,但是它又快速又简单,并且除非您的文档太花哨,否则它就可以完成工作。
答案 3 :(得分:0)
我建议使用json。 JSON格式是一种处理对象到字符串或从字符串到对象操作的标准方法。唯一的缺点是它不适用于非内置的python对象(例如:类似numpy数组)。但是,通过实现正确的Json编码器和Json解码器可以轻松避免这种情况。这是一个示例:
import json
import numpy as np
class NumpyAwareJSONEncoder(json.JSONEncoder):
"""Overrides the default json encoder to allow the encoding of numpy arrays."""
def default(self, obj):
if isinstance(obj, np.ndarray):
return {"__numpy__": True, "data": list(obj)}
# else return default value
return super().default(obj)
class NumpyAwareJSONDecoder(json.JSONDecoder):
"""Same thing as the encoder above but for the decode part."""
def default(self, obj):
obj = super().decode(obj)
if not isinstance(obj, dict):
return obj
elif "__numpy__" not in obj:
return obj
if obj["__numpy__"]:
return np.array(obj["data"])
to_convert = [some fancy list with non-built-in objects]
# write data to file
with open(path_to_file, "w") as f:
json.dump(to_convert, f, cls=NumpyAwareJSONEncoder)
# now read
with open(path_to_file, "r") as f:
data = json.load(f, cls=NumpyAwareJSONDecoder)
您可以查看官方文档here。