将 pickle-able 属性添加到 numpy.ndarray 的子类
Adding a pickle-able attribute to a subclass of numpy.ndarray
我想将 属性 (.csys
) 添加到 numpy.ndarray 的子类中:
import numpy as np
class Point(np.ndarray):
def __new__(cls, arr, csys=None):
obj = np.asarray(arr, dtype=np.float64).view(cls)
obj._csys = csys
return obj
def __array_finalize__(self, obj):
if obj is None: return
self._csys = getattr(obj, '_csys', None)
@property
def csys(self):
print('Getting .csys')
return self._csys
@csys.setter
def csys(self, csys):
print('Setting .csys')
self._csys = csys
然而,当我运行这个测试代码时:
pt = Point([1, 2, 3])
pt.csys = 'cmm'
print("pt.csys:", pt.csys)
# Pickle, un-pickle, and check again
import pickle
pklstr = pickle.dumps(pt)
ppt = pickle.loads(pklstr)
print("ppt.csys:", ppt.csys)
似乎无法 pickle 属性:
Setting .csys
Getting .csys
pt.csys: cmm
Getting .csys
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
C:\Rut\Vanes\bin\pointtest.py in <module>()
39 ppt = pickle.loads(pklstr)
40
---> 41 print("ppt.csys:", ppt.csys)
C:\Rut\Vanes\bin\point.py in csys(self)
15 def csys(self):
16 print('Getting .csys')
---> 17 return self._csys
18
19 @csys.setter
AttributeError: 'Point' object has no attribute '_csys'
我尝试在不使用装饰器的情况下做同样的事情(例如定义 get_csys()
和 set_csys()
,加上 csys = property(__get_csys, __set_csys)
,但结果相同。
我在 Python 3.6.3
下使用 numpy 1.13.3
这个问题已经有人提出并回答了here。简而言之,numpy 使用 __reduce__
和 __setstage__
来 pickle 自身。适应上述情况的覆盖如下所示:
def __reduce__(self):
# Get the parent's __reduce__ tuple
pickled_state = super().__reduce__()
# Create our own tuple to pass to __setstate__
new_state = pickled_state[2] + (self._csys,)
# Return a tuple that replaces the parent's __setstate__ tuple with our own
return (pickled_state[0], pickled_state[1], new_state)
def __setstate__(self, state):
self._csys = state[-1] # Set the _csys attribute
# Call the parent's __setstate__ with the other tuple elements.
super().__setstate__(state[0:-1])
另请注意,在这种简单情况下,getter 和 setter 方法(分别在 @property
和 @csys.getter
装饰器下)并不是严格必需的。如果它们被免除,直接访问 .csys
,而不是通过 'private' ._csys
属性。
我想将 属性 (.csys
) 添加到 numpy.ndarray 的子类中:
import numpy as np
class Point(np.ndarray):
def __new__(cls, arr, csys=None):
obj = np.asarray(arr, dtype=np.float64).view(cls)
obj._csys = csys
return obj
def __array_finalize__(self, obj):
if obj is None: return
self._csys = getattr(obj, '_csys', None)
@property
def csys(self):
print('Getting .csys')
return self._csys
@csys.setter
def csys(self, csys):
print('Setting .csys')
self._csys = csys
然而,当我运行这个测试代码时:
pt = Point([1, 2, 3])
pt.csys = 'cmm'
print("pt.csys:", pt.csys)
# Pickle, un-pickle, and check again
import pickle
pklstr = pickle.dumps(pt)
ppt = pickle.loads(pklstr)
print("ppt.csys:", ppt.csys)
似乎无法 pickle 属性:
Setting .csys
Getting .csys
pt.csys: cmm
Getting .csys
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
C:\Rut\Vanes\bin\pointtest.py in <module>()
39 ppt = pickle.loads(pklstr)
40
---> 41 print("ppt.csys:", ppt.csys)
C:\Rut\Vanes\bin\point.py in csys(self)
15 def csys(self):
16 print('Getting .csys')
---> 17 return self._csys
18
19 @csys.setter
AttributeError: 'Point' object has no attribute '_csys'
我尝试在不使用装饰器的情况下做同样的事情(例如定义 get_csys()
和 set_csys()
,加上 csys = property(__get_csys, __set_csys)
,但结果相同。
我在 Python 3.6.3
下使用 numpy 1.13.3这个问题已经有人提出并回答了here。简而言之,numpy 使用 __reduce__
和 __setstage__
来 pickle 自身。适应上述情况的覆盖如下所示:
def __reduce__(self):
# Get the parent's __reduce__ tuple
pickled_state = super().__reduce__()
# Create our own tuple to pass to __setstate__
new_state = pickled_state[2] + (self._csys,)
# Return a tuple that replaces the parent's __setstate__ tuple with our own
return (pickled_state[0], pickled_state[1], new_state)
def __setstate__(self, state):
self._csys = state[-1] # Set the _csys attribute
# Call the parent's __setstate__ with the other tuple elements.
super().__setstate__(state[0:-1])
另请注意,在这种简单情况下,getter 和 setter 方法(分别在 @property
和 @csys.getter
装饰器下)并不是严格必需的。如果它们被免除,直接访问 .csys
,而不是通过 'private' ._csys
属性。