少なくとも5つの6つの方法があります。推奨される方法は、ユースケースによって異なります。
オプション1:asdict()メソッドを追加するだけです。
問題の説明に基づいて、asdict他の回答で提案されていることを行う方法を非常に検討します。これは、オブジェクトが実際にはコレクションの多くであるようには見えないためです。
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
以下の他のオプションを使用すると、どのオブジェクトメンバーが反復されるか、キーと値のペアとして指定されるかが明確でない限り、他の人を混乱させる可能性があります。
オプション1a:クラスを'typing.NamedTuple'(またはほとんど同等の'collections.namedtuple')から継承し、提供されている_asdictメソッドを使用します。
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
名前付きタプルを使用することは、_asdictメソッドを含め、最小限の労力でクラスに多くの機能を追加するための非常に便利な方法です。ただし、上記のように、NTにはすべてのメンバーが含まれるという制限があり_asdictます。
辞書に含めたくないメンバーがある場合は、_asdict結果を変更する必要があります。
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
def _asdict(self):
d = super()._asdict()
del d['sum']
del d['version']
return d
もう1つの制限は、NTが読み取り専用であることです。これは望ましい場合と望ましくない場合があります。
オプション2:実装し__iter__ます。
このように、例えば:
def __iter__(self):
yield 'a', self.a
yield 'b', self.b
yield 'c', self.c
今、あなたはただすることができます:
dict(my_object)
これが機能するのは、dict()コンストラクターが反復可能な(key, value)ペアを受け入れて辞書を構築するためです。これを行う前に、この方法でオブジェクトを一連のキーと値のペアとして反復することは、作成には便利ですがdict、他のコンテキストでは実際に驚くべき動作になるかどうかを自問してください。たとえば、list(my_object)「...の振る舞いはどうあるべきか」という質問を自問してください。
さらに、get itemobj["a"]構文を使用して値に直接アクセスすることはできず、キーワード引数の解凍も機能しないことに注意してください。そのためには、マッピングプロトコルを実装する必要があります。
オプション3: マッピングプロトコルを実装します。これにより、キーによるアクセス動作、dictを使用せずにへのキャストが可能になり、すべてのキーが文字列()の場合、__iter__アンパック動作({**my_obj})およびキーワードアンパック動作も提供されますdict(**my_obj)。
マッピングプロトコルでは、(少なくとも)2つのメソッドを一緒に提供する必要があります:keys()と__getitem__。
class MyKwargUnpackable:
def keys(self):
return list("abc")
def __getitem__(self, key):
return dict(zip("abc", "one two three".split()))[key]
これで、次のようなことができます。
>>> m=MyKwargUnpackable()
>>> m["a"]
'one'
>>> dict(m)
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m)
{'a': 'one', 'b': 'two', 'c': 'three'}
上記のように、十分に新しいバージョンのpythonを使用している場合は、マッピングプロトコルオブジェクトを次のように辞書内包表記に解凍することもできます(この場合、キーが文字列である必要はありません)。
>>> {**m}
{'a': 'one', 'b': 'two', 'c': 'three'}
マッピングプロトコルはそのノートよりも優先さ__iter__にオブジェクトをキャストする際の方法dict(すなわち、kwargアンパックを使用せずに直接dict(m))。したがって、反復可能として使用した場合(たとえば、list(m))とdict(dict(m))にキャストした場合で、オブジェクトの動作を変えることができ、場合によっては便利です。
強調:マッピングプロトコルを使用することができるからといって、あなたがいることを意味するものではありませんすべきで、そう。オブジェクトがキーと値のペアのセットとして、またはキーワードの引数と値として渡されることは実際に意味がありますか?辞書のように、キーでアクセスすることは本当に意味がありますか?
これらの質問に対する答えが「はい」の場合は、次のオプションを検討することをお勧めします。
オプション4:'collections.abc'モジュールの使用を検討します。
クラスを他のユーザーから継承する'collections.abc.Mappingか'collections.abc.MutableMapping、他のユーザーに通知することで、すべての目的と目的で、クラスはマッピング*であり、そのように動作することが期待できます。
dict必要に応じてオブジェクトをキャストすることもできますが、そうする理由はおそらくほとんどありません。ダックタイピングのため、マッピングオブジェクトをにキャストするdict手間は、ほとんどの場合、追加の不要な手順になります。
この答えも役立つかもしれません。
以下のコメントに記載されているように、これをabcの方法で行うと、基本的にオブジェクトクラスが同様のクラスに変わりますdict(MutableMapping読み取り専用のMapping基本クラスではなく、を使用すると仮定します)。でできることはすべてdict、独自のクラスオブジェクトで行うことができます。これは望ましい場合と望ましくない場合があります。
また、numbersモジュール内の数値abcsを確認することも検討してください。
https://docs.python.org/3/library/numbers.html
オブジェクトもにキャストしているので、キャストが不要になるようintに、クラスを本格的に変換する方が理にかなってintいる場合があります。
オプション5:便利なユーティリティメソッドを含むdataclassesモジュール(Python 3.7のみ)の使用を検討しasdict()ます。
from dataclasses import dataclass, asdict, field, InitVar
@dataclass
class Wharrgarbl(object):
a: int
b: int
c: int
sum: InitVar[int]
version: InitVar[str] = "old"
def __post_init__(self, sum, version):
self.sum = 6
self.version = str(version)
今、あなたはこれを行うことができます:
>>> asdict(Wharrgarbl(1,2,3,4,"X"))
{'a': 1, 'b': 2, 'c': 3}
オプション6:Python3.8で追加されたtyping.TypedDictを使用します。
注:オプション6は、OPまたはこの質問のタイトルに基づく他の読者が探しているものではない可能性があります。以下の追加コメントを参照してください。
class Wharrgarbl(TypedDict):
a: str
b: str
c: str
このオプションを使用すると、結果のオブジェクトがあるdict(強調:それはされませんWharrgarbl)。それを口述に「キャスト」する理由はまったくありません(コピーを作成している場合を除く)。
また、オブジェクトはであるdictため、初期化署名はの署名と同じでdictあり、キーワード引数または別の辞書のみを受け入れます。
>>> w = Wharrgarbl(a=1,b=2,b=3)
>>> w
{'a': 1, 'b': 2, 'c': 3}
>>> type(w)
<class 'dict'>
強調:上記の「クラス」Wharrgarblは実際にはまったく新しいクラスではありません。これはdict、タイプチェッカーのさまざまなタイプのフィールドを持つ型付きオブジェクトを作成するための単なる構文糖衣です。
そのため、このオプションは、コードのリーダー(およびmypyなどのタイプチェッカー)に、そのようなdictオブジェクトが特定の値型を持つ特定のキーを持つことが期待されていることを通知するのに非常に便利です。
ただし、これは、たとえば、次のことを試すことはできても、他のメソッドを追加できないことを意味します。
class MyDict(TypedDict):
def my_fancy_method(self):
return "world changing result"
...しかし、それは機能しません:
>>> MyDict().my_fancy_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'my_fancy_method'
※「マッピング」は、dictダックタイピングのような標準的な「名前」になりました。