2017-05-03 8 views
1

pickled複雑なenumインスタンスをunpickleしようとすると、常にValueError:BLUEは有効なColorsではありません。Pythonで複雑な列挙型をpickleする方法

どのようにピックルしてアンピッキングする方法はありますか?

from pickle import loads, dumps 
from enum import Enum 


class ColorType(object): 

    def __init__(self, counter, name): 
     self.counter = counter 
     self.name = name 

    def __str__(self): 
     return self.name 


class Colors(Enum): 
    GREEN = ColorType(1, 'GREEN') 
    BLUE = ColorType(2, 'BLUE') 


color = Colors.BLUE 
print(color is loads(dumps(color))) 

私はPython 2.7を使用しています。

+0

おそらくあなたは 'enum34'バックポートパッケージを使用していますか? –

+0

そしてなぜあなたは 'ColorType'クラスを使用していますか? IIRC「Enum」は、別のクラスオブジェクトを使用せずに、追加のメソッドを直接含むより複雑な値型をサポートしています。例については、ドキュメンテーションを参照してください。 –

+0

はい、私は 'enum34'をインストールしました。この例は実際の問題をはるかに複雑なものにするためのものです。 –

答えて

2

列挙型の値としてカスタムクラスを使用しないでください。ここには必要ありません。まったく別のクラスを必要としないあなたの具体的な例は、あなただけ使用できます。

class Colors(Enum): 
    GREEN = 1 
    BLUE = 2 

    def __str__(self): 
     return self.name 

    @property 
    def counter(self): 
     return self.value 

これは良くstr().counter行動を持っています。コードでstr()Color.<name>に直接送信するのではなく、Color.<name>.valueに適用する必要があります。

その他のカスタムメソッドと属性については、それらをサブクラスEnumに直接置くと、それらもenumメンバーの一部になります。エントリごとにさらに値が必要な場合は、タプルを設定し、__init__メソッドでそのタプルを引き離します。ドキュメントにはこれをさらに詳しく示すPlanet exampleがあります。

デモ:

>>> Colors.BLUE 
<Colors.BLUE: 2> 
>>> Colors.BLUE.value 
2 
>>> Colors.BLUE.counter 
2 
>>> str(Colors.BLUE) 
'BLUE' 
>>> Colors.BLUE is loads(dumps(Colors.BLUE)) 
True 
+0

ありがとう、私は自分のメソッドを 'Colors'列挙型に直接置きました。 –

0

ここでの問題は、基本的な平等である:Colorsは、それが失敗しているColorType(2, 'BLUE')のアンピックル値の一致を見つけようとしているので

>>> ColorType(2, 'BLUE') == ColorType(2, 'BLUE') 
False 

解決策は単純です: `ColorTypeです 'に__eq____ne__メソッドを追加:

class ColorType(object): 

    def __init__(self, counter, name): 
     self.counter = counter 
     self.name = name 

    def __str__(self): 
     return self.name 

    def __eq__(self, other): 
     return self.name == other.name and self.counter == other.counter 

    def __ne__(self, other): 
     # not needed in Python 3 
     return self.name != other .name or self.counter != other.counter 

NB私はほとんどの場合、あなただけのEnum自体に必要な機能を追加する必要があることを@MartijnPietersに同意します。

+0

しかし、なぜ2番目のクラス*は最初の*ですか? –

+0

'aenum'を使用しない場合、属性アクセスを取得する簡単な方法は' namedtuple'を混在させることです。要点は、それが必要な場合にはそれができるということです。 (いいえ、自分でユースケースを持っていません。) –

+0

Python 3では、 '__ne__'が' __ne__'を委譲して結果を反転させるため、 '__ne__'はオプションです。](https://docs.python.org/3/reference/datamodel.html#object.__ne__ )。残念ながら、Python 2ではあなたはあまり運がないです。 –

関連する問題