Добавление атрибута pickle-способны к подклассу numpy.ndarray - PullRequest
0 голосов
/ 17 мая 2018

Я хотел бы добавить свойство (.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)

представляется, что атрибут не может быть выбран:

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), но у меня был тот же результат с этим.

Я использую numpy 1.13.3 под Python 3.6.3

1 Ответ

0 голосов
/ 17 мая 2018

На этот вопрос уже задавали и отвечали здесь .В двух словах, numpy использует __reduce__ и __setstage__ для засолки.Переопределения, адаптированные к описанному выше случаю, выглядят так:

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.

...