2012-01-23 6 views
12

J'ai été surpris de constater que python (version 3.2.2) refusait de décaper un objet parce que son dict contenait une référence à Ellipsis. De l'autre built-in constants, cornichon est heureux de travailler avec False, True, et None, comme indiqué explicitement dans le pickle documentation, mais étouffe également sur NotImplemented.Pourquoi Ellipsis et NotImplemented ne peuvent-ils pas être décapés?

Python 3.2.2 (default, Sep 5 2011, 21:17:14) 
[GCC 4.6.1] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import pickle 
>>> pickle.dumps(True) 
b'\x80\x03\x88.' 
>>> pickle.dumps(False) 
b'\x80\x03\x89.' 
>>> pickle.dumps(None) 
b'\x80\x03N.' 
>>> pickle.dumps(Ellipsis) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
_pickle.PicklingError: Can't pickle <class 'ellipsis'>: attribute lookup builtins.ellipsis failed 
>>> pickle.dumps(NotImplemented) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
_pickle.PicklingError: Can't pickle <class 'NotImplementedType'>: attribute lookup builtins.NotImplementedType failed 

Pour être complet, des constantes intégrées moins utiles, __debug__ est juste un bool, provoque donc pas de problèmes; copyright, license, et credits travail (leur type est site._Printer); quit et exit pas (leur type est site.Quitter, qui ne peut pas être trouvé car il est défini dans une fonction).

Quelqu'un peut-il expliquer pourquoi c'est - sûrement Ellipsis et NotImplemented n'ont pas été négligés? La seule information pertinente que je peux trouver est this bug, qui se plaint que NoneType (c'est-à-dire type(None)) n'est pas décollable. Un des commentateurs mentionne que type(Ellipsis) et type(NotImplemented) ne peuvent pas être décapés, apparemment sans remarquer que leurs instances ne peuvent pas être non plus.

+2

omission Odd, mais on pourrait dire que vous êtes censé ne pas vraiment garder les références à ces valeurs pour commencer. – millimoose

+0

@Inderdial: mon cas d'utilisation particulier était dans un conteneur qui garde la trace des tranches qui ont été accédées. Puisque les tranches peuvent être décapées, il semble étrange que Ellipsis (qui est vraiment juste un genre spécial de tranche) ne peut pas. Stocker une référence 'NotImplemented' est probablement moins susceptible d'être utile, bien que j'imagine que quelqu'un pourrait vouloir pour une sorte de schéma de comparaison compliqué. – James

+1

@James - Strictement parlant, 'Ellipsis' n'est pas un genre particulier de tranche, mais son interprétation est absolument définie par l'utilisateur. En Numpy, il s'agit plus d'une séquence de zéro ou plusieurs tranches, déterminée automatiquement. –

Répondre

1

Citant les documentation:

Les types suivants peuvent être décapés:

  • Aucun, vrai et faux
  • entiers, nombres à virgule flottante, nombres complexes
  • chaînes, octets , bytearrays
  • tuples, listes, ensembles et dictionnaires ne contenant que des objets picklables
  • fonctions définies au niveau supérieur d'un module
  • fonctions intégrées définies au niveau supérieur d'un module
  • classes qui sont définies au niveau supérieur d'un cas le module
  • de ces classes dont __dict__ ou __setstate __() est picklable (voir la section décapage classe instances pour plus de détails)

Les deux objets en question, Ellipsis et NotImplemented, ne sont pas conformes à l'une de ces règles, et par conséquent ne peut pas être pic kled.

Je doute qu'il y ait une meilleure raison de ne pas inclure toutes les constantes intégrées dans la première règle, sauf que personne n'en a vu le besoin. Si vous pensez vraiment que pickle devrait supporter cela, pensez à poster une demande de fonctionnalité (mieux vaut apporter un cas d'utilisation convaincant!).

+0

J'ai vu cette liste, mais je ne savais pas si c'était exclusif. En particulier, les fonctions intégrées comme 'map' et' open' peuvent être décapées, mais ne semblent correspondre à aucun de ces critères (sauf si vous les considérez comme 'définies au niveau supérieur d'un module', auquel cas semble étrange que les goûts de 'NoneType' ne peuvent pas être décapés). – James

+2

'map' et' open' sont définis au niveau supérieur du module '__builtin__' (essayez' import __builtin__ as B; B.map'), 'NoneType' est une classe intégrée, pas une fonction. La documentation me semble cohérente! –

+0

Hmm, c'est logique - merci pour l'explication (mais maintenant je me demande où NoneType est défini, si n'importe où!). Bien que je voulais vraiment savoir ce que le raisonnement derrière ce comportement est - peut-être que je devrais simplement soumettre un rapport de bogue. – James

4

Il n'y a absolument aucune raison pour python de ne pas décaper des choses comme Ellipsis et NotImplemented, et franchement ne pas les avoir picklable contribue à la fragilité de python comme un langage parallèle/asynchrone. Vous pouvez décaper ces types d'objets avec dill, un remplacement pour pickle.Oui, je suis conscient que c'est une diatribe légère, mais je pense qu'un NotImplemented dans votre code cible ne devrait pas vous empêcher d'utiliser multiprocessing ou un autre de python parallèle ... ou d'enregistrer l'état de votre session Python pour une utilisation ultérieure … ou peu importe.

Python 3.2.5 (default, May 19 2013, 14:25:55) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> dill.dumps(True) 
b'\x80\x03\x88.' 
>>> dill.dumps(False) 
b'\x80\x03\x89.' 
>>> dill.dumps(None) 
b'\x80\x03N.' 
>>> dill.dumps(Ellipsis) 
b'\x80\x03cdill.dill\n_eval_repr\nq\x00X\x08\x00\x00\x00Ellipsisq\x01\x85q\x02Rq\x03.' 
>>> dill.dumps(NotImplemented) 
b'\x80\x03cdill.dill\n_eval_repr\nq\x00X\x0e\x00\x00\x00NotImplementedq\x01\x85q\x02Rq\x03.' 

Obtenez dill ici: https://github.com/uqfoundation/dill

+0

Merci pour cela-- il m'a fait regarder et j'ai trouvé ce lien qui m'a aidé à résoudre mon problème de parallélisation dans IPython: http://nbviewer.ipython.org/gist/anonymous/5241793 – Omegaman

+0

@GB: génial. C'est un bon lien que vous avez posté. Je suis également conscient que 'dill' est utilisé comme un remplacement de pickle dans' multiprocessing', 'mpi4py', et un autre paquet python utilisé en parallèle. –

Questions connexes