我的项目的一个重要部分是能够将类实例保存和加载到文件中。为了进一步了解上下文,我的类同时具有一组属性和一些方法。
到目前为止,我已经尝试使用pickle,但它并没有按预期工作。对于初学者来说,它不会加载方法,也不会让我添加最初定义的属性;换句话说,它并没有真正复制我可以使用的类。
相关代码:
class Brick(object):
def __init__(self, name, filename=None, areaMin=None, areaMax=None, kp=None):
self.name = name
self.filename = filename
self.areaMin = areaMin
self.areaMax = areaMax
self.kp = kp
self.__kpsave = None
if filename != None:
self.__logfile = file(filename, 'w')
def __getstate__(self):
f = self.__logfile
self.__kpsave = []
for point in self.kp:
temp = (point.pt, point.size, point.angle, point.response, point.octave, point.class_id)
self.__kpsave.append(temp)
return (self.name, self.areaMin, self.areaMax, self.__kpsave,
f.name, f.tell())
def __setstate__(self, state):
self.value, self.areaMin, self.areaMax, self.__kpsave, name, position = state
f = file(name, 'w')
f.seek(position)
self.__logfile = f
self.filename = name
self.kp = []
for point in self.__kpsave:
temp = cv2.KeyPoint(x=point[0][0], y=point[0][1], _size=point[1], _angle=point[2], _response=point[3],
_octave=point[4], _class_id=point[5])
self.kp.append(temp)
def calculateORB(self, img):
pass #I've omitted the actual method here
(还有一些属性和方法,但它们不相关)
现在,这个类定义在创建新实例时工作得很好:我可以只用名称创建一个新的 Brick,然后我可以设置 areaMin 或任何其他属性,并且我可以使用 pickle(cPickle) 转储当前实例到一个文件就好了(我使用这些 getstate 和 setstate 因为 pickle 不能与 OpenCV 的 Keypoint 元素一起使用)。
当然,当我加载实例时,问题就来了:使用 pickle load() 我可以从文件加载实例,并且我之前设置的值将在那里(即我如果我确实为其设置了值,则可以访问 areaMin 就可以了)但如果我从未更改过任何其他属性的值,则无法访问任一方法或将值添加到任何其他属性。我注意到,如果我只是从完全不同的源文件中进行酸洗,我也不需要导入
我的类定义。
由于我想做的就是从我的类对象构建一个“数据库”,那么解决这个问题的最佳方法是什么?我知道应该工作的是简单地编写一个 .Save()
方法来写入一个 .py 源文件,我本质上在其中创建该类的实例,这样我就可以然后 .Load()
它将根据需要执行 exec
和 eval
,但是,这似乎是最糟糕的方法,所以,我实际上应该怎么做?
谢谢。
最佳答案
您不应该尝试在 __getstate__
和 __setstate__
方法中执行 I/O - 这些方法由 Pickle 调用,并且扩展结果只是内存中的对象可以进一步腌制。
此外,如果你的“self.kp”属性中的“Point”类只是一个常规的Python类,那么你根本不需要自定义pickling -
您需要担心的是在调用 Pickle 时处理 I/O。如果您确实需要独立加载不同的实例,您可以求助于“shelve”模块,或者更好的是,使用 pickle.dumps 并将结果字符串存储在 DBMS 中(可以是内置的 sqlite)。
总而言之:
class Point(object):
...
class Brick(object):
def __init__(self, point, ...):
self.kp = point
然后,将单个对象保存到文件中:
with open("filename.pickle", "wb") as file_:
pickle.dump(my_brick, file_, -1)
并恢复:
my_brick = pickle.load(open("filename.pickle", "rb", -1)
要存储多个实例并一次恢复所有实例,您可以只需按顺序转储到同一个打开的文件,然后它们一个一个地读取,直到由于“空文件”而出现错误- 或者您可以简单地将要保存的所有对象添加到列表中,然后立即腌制整个列表。
要保存和检索任意对象,您可以通过提供“名称”或“id”等属性来检索这些对象 - 您可以使用搁置模块:https://docs.python.org/3/library/shelve.html或者如果您需要复杂的查询等,请使用真实的数据库。尝试编写自己的临时二进制格式以允许搜索所需的实例是一个可怕的想法 - 因为您必须实现该文件 0 读取、写入、保护、极端情况等的所有协议(protocol)。
关于python - 从文件保存和加载类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43372451/