我有一个相当大的项目,包括最近需要使用@property
装饰器更新的类Foo,以创建自定义的getter和setter方法。
我还在我的硬盘上存储了几个Foo
的实例,在某些时候我可能需要重新加载。我的问题是,我无法访问这些旧对象上的属性decoreted属性。
考虑以下示例:
import pickle
# define Class and create instance
class Foo:
def __init__(self):
self.val = 1
foo = Foo()
# dump foo into file
with open("foo.pickle", 'wb') as handle:
pickle.dump(foo, handle, pickle.HIGHEST_PROTOCOL)
# overwrite and add @property in the class definition
class Foo:
def __init__(self):
self._val = "new_foo"
@property
def val(self):
return self._val
@val.setter
def val(self, val):
self._val = val
foo_new = Foo()
print(foo_new.val)
# reload foo
with open("foo.pickle", "rb") as handle:
foo_old = pickle.load(handle)
# try to access attributes
print(foo_old.val)
最后一行提出:
NameError:未定义名称“_val”
我还有哪些选项可以访问归档实例的属性?
修改:在第二个Foo定义的构造函数中将self.val
更改为self._val
。
答案 0 :(得分:2)
泡菜documentation说:
当一个类实例被unickled时,它的
__init__()
方法通常不被调用。
这就是未定义_val
属性的原因您可以通过在替换__new__
类中定义Foo
方法并在其中设置实例属性来解决此问题:
import pickle
# define Class and create instance
class Foo:
def __init__(self):
self.val = 1
foo = Foo()
# dump foo into file
with open("foo.pickle", 'wb') as handle:
pickle.dump(foo, handle, pickle.HIGHEST_PROTOCOL)
# overwrite and add @property in the class definition
class Foo:
def __new__(cls, val=None):
inst = super().__new__(cls)
inst._val = "new_foo" if val is None else val
return inst
@property
def val(self):
return self._val
@val.setter
def val(self, val):
self._val = val
foo_new = Foo()
print(foo_new.val) # -> new_foo
# reload foo
with open("foo.pickle", "rb") as handle:
foo_old = pickle.load(handle)
print(foo_old.val) # -> new_foo
答案 1 :(得分:1)
这可能是彻头彻尾的黑客 - 我不确定。但是,我能够使用以下代码重建从第一个“Foo”类中腌制的对象;
import pickle
class Foo:
def __init__(self):
self._val = "new_foo"
@property
def val(self):
try:
return self._val
except AttributeError:
self._val = self.__dict__['val']
self.__dict__.pop('val')
return self._val
@val.setter
def val(self, val):
self._val = val
with open("foo.pickle", "rb") as handle:
foo_old = pickle.load(handle)
print(foo_old.val)
答案 2 :(得分:1)
可能是使用自定义Unpickler
,尽管您需要保留旧类(使用不同的名称,如果需要,可以隐藏)并定义将旧类的对象转换为新的那一个。这是一个基本的例子:
a