2012-01-23 15 views
12

Sono stato sorpreso di scoprire che Python (versione 3.2.2) si rifiutava di decapitare un oggetto perché il suo dict conteneva un riferimento a Ellipsis. Tra gli altri built-in constants, pickle è felice di lavorare con False, True e None, come esplicitamente dichiarato nello pickle documentation, ma anche in soppressione NotImplemented.Perché Ellipsis e NotImplemented non possono essere decapitati?

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 

Per completezza, i meno utili costanti incorporate, __debug__ è solo un bool, quindi non causa problemi; copyright, license e credits funzionano (il loro tipo è site._Printer); quit e exit non (il loro tipo è site.Quitter, che non può essere trovato poiché è definito all'interno di una funzione).

Qualcuno può spiegare perché questo è - sicuramente Ellipsis e NotImplemented non sono stati trascurati? L'unica informazione rilevante che posso trovare è this bug, che lamenta che NoneType (ovvero, type(None)) non è selezionabile. Uno dei commentatori menziona che type(Ellipsis) e type(NotImplemented) non possono essere decapitati, apparentemente senza notare che le loro istanze non possono essere neanche.

+2

omissione Dispari, anche se si potrebbe sostenere che non dovresti davvero a mantenere i riferimenti a quei valori per cominciare. – millimoose

+0

@Inderdial: il mio caso d'uso particolare era in un contenitore che tiene traccia delle fette a cui è stato effettuato l'accesso. Poiché le fette possono essere decapate, sembra strano che Ellipsis (che è davvero solo un tipo speciale di fetta) non può. Memorizzare un riferimento a "NotImplemented" è probabilmente meno probabile che sia utile, anche se posso immaginare che qualcuno possa volerlo per qualche tipo di complicato schema di confronto. – James

+1

@James - A rigor di termini, 'Ellipsis' non è un tipo speciale di slice, ma la sua interpretazione è assolutamente definita dall'utente. In Numpy, è più simile a una sequenza di zero o più sezioni, determinata automaticamente. –

risposta

1

Citando le documentation:

I seguenti tipi possono essere decapati:

  • Nessuno, True e False
  • interi, numeri in virgola mobile, numeri complessi
  • stringhe, byte , bytearys
  • tuple, elenchi, set e dizionari contenenti solo oggetti selezionabili
  • funzioni definite al livello superiore di un modulo
  • funzioni incorporate definiti a livello superiore di un modulo
  • classi definite al livello superiore di un modulo
  • istanze di tali classi i cui __dict__ o __setstate __() è serializzabili (vedi istanze sezione decapaggio classe per dettagli)

i due oggetti in questione, Ellipsis e NotImplemented, non conformi a una di queste regole, e di conseguenza non possono essere pic KLED.

Dubito che ci sia un motivo migliore per non includere tutte le costanti incorporate nella prima regola tranne che nessuno ha visto la necessità di farlo. Se pensi davvero che pickle debba supportarlo, considera di postare una richiesta di funzionalità (meglio portare un caso d'uso convincente!).

+0

Ho visto quella lista, ma non ero sicuro se fosse esclusiva. In particolare, le funzioni incorporate come 'map' e' open' possono essere decapate, ma non sembrano adattarsi a nessuno di questi criteri (a meno che non li consideri "definiti al livello più alto di un modulo", nel qual caso sembra strano che i like di "NoneType" non possano essere decapitati). – James

+2

'map' e' open' sono definiti al livello più alto del modulo '__builtin__' (prova 'import __builtin__ come B; B.map'),' NoneType' è una classe built-in, non una funzione. La documentazione mi sembra coerente! –

+0

Hmm, questo ha un senso - grazie per la spiegazione (anche se ora mi chiedo dove si definisce NoneType, se esiste!). Anche se volevo davvero sapere qual è il ragionamento alla base di questo comportamento, forse dovrei semplicemente inviare una segnalazione di errore. – James

4

Non c'è assolutamente alcun motivo per Python di non mettere a soqquadro cose come Ellipsis e NotImplemented, e francamente il fatto di non averli picklable contribuisce alla fragilità di python come linguaggio parallelo/asincrono. Puoi mettere sottaceti questi tipi di oggetti con dill, una sostituzione per pickle.Sì, sono consapevole che si tratta di un lieve slancio, ma penso che uno NotImplemented nel codice di destinazione non dovrebbe impedirti di utilizzare multiprocessing o qualche altro da python parallelo ... o di salvare lo stato della tua sessione python per l'uso in un secondo momento ... o qualsiasi altra cosa

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.' 

Get dill qui: https://github.com/uqfoundation/dill

+0

Grazie per questo-- mi ha fatto guardare e ho trovato questo collegamento che mi ha aiutato a risolvere il mio problema parallelizzando in IPython: http://nbviewer.ipython.org/gist/anonymous/5241793 – Omegaman

+0

@GB: fantastico. Questo è un buon link che hai postato. Sono anche consapevole del fatto che 'dill' viene usato come sostituto di pickle in' multiprocessing', 'mpi4py', e in altri pacchetti python usati nel calcolo parallelo. –

Problemi correlati