Как выбрать функции класса python-attrs через cloudpickle? - PullRequest
0 голосов
/ 31 октября 2018

Я использую cloudpickle для передачи функций, и я хотел бы передать функцию класса attrs через cloudpickle.

import pickle
import attr

@attr.s(auto_attribs=True)
class myclass:
    an_int: int
    a_str: str
    a_float: float

    def myfunc(self):
        return f"{self.an_int} + {self.a_str} + {self.a_float}"

mc = myclass(1, "test", 2.4)
f = pickle.loads(pickle.dumps(mc.myfunc))
print(f())

выполнение этого дает мне 1 + test + 2.4

В то время как реализация Cloudpickle

import attr
import cloudpickle

@attr.s(auto_attribs=True)
class myclass:
    an_int: int
    a_str: str
    a_float: float

    def myfunc(self):
        return f"{self.an_int} + {self.a_str} + {self.a_float}"

mc = myclass(1, "test", 2.4)
f = cloudpickle.loads(cloudpickle.dumps(mc.myfunc))
print(f())

выдает ошибку: TypeError: can't pickle _thread._local objects (я опубликую полный журнал ошибок внизу)

Я уверен, что мне нужно реализовать какую-то функцию __getstate__ или __reduce__, чтобы заставить облачный рассол мариновать класс, но я попробовал оба без удачи.

добавление функции:

def __reduce__(self):
    return (self.__class__, (self.an_int, self.a_str, self.a_float))

выдает ту же ошибку

Что я должен реализовать для достижения этой цели?

журнал ошибок Python:

Traceback (most recent call last):
  File "x.py", line 16, in <module>
    f = cloudpickle.loads(cloudpickle.dumps(mc.myfunc))
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 917, in dumps
    cp.dump(obj)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 268, in dump
    return Pickler.dump(self, obj)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 437, in dump
    self.save(obj)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 689, in save_instancemethod
    self.save_reduce(types.MethodType, (obj.__func__, obj.__self__), obj=obj)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 638, in save_reduce
    save(args)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 771, in save_tuple
    save(element)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 549, in save
    self.save_reduce(obj=obj, *rv)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 633, in save_reduce
    save(cls)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 664, in save_global
    return self.save_dynamic_class(obj)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 511, in save_dynamic_class
    save(clsdict)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 882, in _batch_setitems
    save(v)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 408, in save_function
    self.save_function_tuple(obj)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/site-packages/cloudpickle/cloudpickle.py", line 573, in save_function_tuple
    save(state)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 882, in _batch_setitems
    save(v)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 882, in _batch_setitems
    save(v)
  File "/home/me/.local/share/pyenv/versions/3.7.0/lib/python3.7/pickle.py", line 524, in save
    rv = reduce(self.proto)
TypeError: can't pickle _thread._local objects

1 Ответ

0 голосов
/ 31 октября 2018

Это вызвано тем, что attrs использует локальные потоки для разбиения циклов объектов в __repr__, а облачный рассол не нравится. Для справки, он был введен в https://github.com/python-attrs/attrs/pull/358.

Ваше быстрое решение - установить @attr.s(repr=False), но не стесняйтесь открывать проблему на нашем баг-трекере, и мы можем обсудить, как действовать.

...