2012-01-23 20 views
12

Zaskoczyło mnie, że pyton (wersja 3.2.2) odmawiał wybrania obiektu, ponieważ jego dykcja zawierała odniesienie do Ellipsis. Spośród innych built-in constants, pikle jest szczęśliwy pracy z False, True i None, jak wyraźnie stwierdzono w pickle documentation, ale również dławiki na NotImplemented.Dlaczego Ellipsis i NotImplemented nie mogą być marynowane?

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 

Dla kompletności, z mniej przydatnych wbudowanych stałych, __debug__ tylko bool, więc nie powoduje żadnych problemów; copyright, license i credits (ich typ to site._Printer); quit i exit nie (ich typ to site.Quitter, którego nie można znaleźć tak, jak jest zdefiniowany w funkcji).

Czy ktoś może wyjaśnić, dlaczego tak jest - z pewnością Ellipsis i NotImplemented nie zostały przeoczone? Jedyną istotną informacją, jaką mogę znaleźć, jest this bug, która narzeka, że ​​NoneType (tj. type(None)) nie można wybrać. Jeden z komentatorów wspomina, że ​​type(Ellipsis) i type(NotImplemented) nie mogą być marynowane, najwyraźniej nie zauważając, że ich instancje też nie mogą być.

+2

Odd pominięcie, choć można by argumentować, że nie jesteś naprawdę powinien zachować odniesień do tych wartości na początek. – millimoose

+0

@Inderdial: mój szczególny przypadek użycia był w kontenerze, który śledzi dostępne plasterki. Ponieważ plasterki mogą być marynowane, wydaje się dziwne, że Ellipsis (który jest tak naprawdę tylko specjalnym plasterkiem) nie może. Przechowywanie odniesienia do 'NotImplemented' jest prawdopodobnie mniej prawdopodobne, ale mogę sobie wyobrazić, że ktoś może tego chcieć dla jakiegoś skomplikowanego schematu porównywania. – James

+1

@ James - Ściśle mówiąc, 'Ellipsis' nie jest specjalnym rodzajem plastra, ale jego interpretacja jest absolutnie zdefiniowana przez użytkownika. W Numpy jest to bardziej jak sekwencja zero lub więcej plasterków, określana automatycznie. –

Odpowiedz

1

Cytując documentation:

następujące typy mogą być marynowane:

  • None, prawda i fałsz
  • liczb całkowitych, liczb zmiennoprzecinkowych, liczby zespolone
  • struny, bajty , bytearrays
  • krotki, listy, zestawy i słowniki zawierające tylko obiekty do wybrania
  • funkcje zdefiniowane w górnym poziomie modułu
  • wbudowane w funkcje zdefiniowane w górnym poziomie modułu
  • klasy, które zostały zdefiniowane w górnym poziomie modułu
  • przykłady takich grup, których __dict__ lub __ __setstate() jest picklable (patrz sekcja instancji Trawienie Class szczegóły)

dwóch obiektów o którym mowa, Ellipsis i NotImplemented, nie są zgodne z któregokolwiek z tych zasad, a tym samym nie może być pic kled.

Wątpię, czy istnieje lepszy powód, aby nie uwzględniać wszystkich wbudowanych stałych w pierwszej regule, poza tym, że nikt nie widział takiej potrzeby. Jeśli naprawdę sądzisz, że pikle powinny to wspierać, rozważ umieszczenie prośby o funkcję (lepiej przynieś przekonujący przypadek użycia!).

+0

Widziałem tę listę, ale nie byłem pewien, czy to było wyłączne. W szczególności wbudowane funkcje takie jak 'map' i' open' mogą być wytrawiane, ale nie wydają się pasować do żadnego z tych kryteriów (chyba że uważasz je za "zdefiniowane na najwyższym poziomie modułu", w takim przypadku to wydaje się dziwne, że takich jak 'NoneType' nie można marynować). – James

+2

'map' i' open' są zdefiniowane na najwyższym poziomie modułu '__builtin__' (spróbuj' import __builtin__ jako B; B.map'), 'NoneType' jest wbudowaną klasą, a nie funkcją. Dokumentacja wydaje mi się spójna! –

+0

Hmm, to ma sens - dziękuję za wyjaśnienie (choć teraz zastanawiam się, gdzie zdefiniowano NoneType, jeśli gdziekolwiek!). Chociaż naprawdę chciałem się dowiedzieć, jakie jest uzasadnienie tego zachowania - może powinienem wysłać zgłoszenie błędu. – James

4

Nie ma żadnego powodu dla Pythona, aby nie podlewać rzeczy takich jak Ellipsis i NotImplemented, i szczerze mówiąc nie mając ich wybieralny przyczynia się do słabości Pythona jako język równoległy/asynchroniczny. Możesz je zbierać za pomocą dill, zamiennika dla pickle.Tak, zdaję sobie sprawę, że jest to łagodny rant, ale myślę, że kod NotImplemented w kodzie docelowym nie powinien uniemożliwiać używania multiprocessing lub innego z równoległego python ... lub zapisywania stanu sesji Pythona do użycia w późniejszym czasie … lub cokolwiek.

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 tutaj: https://github.com/uqfoundation/dill

+0

Dzięki za to-- to mnie szukał i znalazłem ten link, który pomógł mi rozwiązać mój problem zrównujący się w IPython: http://nbviewer.ipython.org/gist/anonymous/5241793 – Omegaman

+0

@GB: super. To dobry link, który opublikowałeś. Jestem również świadomy, że 'dill' jest używany jako zamiennik pikla w' multiprocessing', 'mpi4py' i niektórych innych pakietach Pythona używanych w obliczeniach równoległych. –

Powiązane problemy