Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cloudpickle drops __dict__ attribute of classes. #282

Open
pierreglaser opened this issue Jun 7, 2019 · 1 comment · May be fixed by #291
Open

cloudpickle drops __dict__ attribute of classes. #282

pierreglaser opened this issue Jun 7, 2019 · 1 comment · May be fixed by #291

Comments

@pierreglaser
Copy link
Member

pierreglaser commented Jun 7, 2019

After #253 (comment), I started examinating these lines. I think the original use-case was to handle classes like namedtuple overloading __dict__.
(even though the test suite passes for all python versions if simply drop the __dict__ item out of clsdict).

__dict__ = clsdict.pop('__dict__', None)
if isinstance(__dict__, property):
type_kwargs['__dict__'] = __dict__

In more detail:

  • The first one line is necessary because updating a __dict__ field in the __dict__ of a class is simply not possible. Indeed, __dict__ attributes are proxies objects and do not support direct item assigment like __dict__[k] = v. Instead, the canonical way to update a class __dict__ is to do setattr(cls, key, value). However, here, key is __dict__, so python thinks we actually want to override the __dict__ attribute of cls, and not a __dict__ field of the __dict__.
  • However, including __dict__ in the type_kwargs only if it is a property object is kind of arbitrary (probably related to namedtuples). Take this example for example, where we loose the __dict__ attribute:
In [1]: import gc 
   ...: import cloudpickle 
   ...:  
   ...: class A: 
   ...:     __dict__ = {'some_attribute':1} 
   ...: a = A() 
   ...: print(f'calling __dict__ on the original A instance: {a.__dict__}') 
   ...:  
   ...: s = cloudpickle.dumps(a) 
   ...: del A 
   ...: del a 
   ...: gc.collect() 
   ...: depickled_a = cloudpickle.loads(s) 
   ...: print(f'calling __dict__ on the depickled A instance: {depickled_a.__dict__}')
calling __dict__ on the original A instance: {'some_attribute': 1}
calling __dict__ on the depickled A instance: {}
@ogrisel
Copy link
Contributor

ogrisel commented Jun 8, 2019

For reference, I tried with Python 2 and I observe the same outcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants