web-dev-qa-db-ja.com

サブクラス化dict:dict .__ init __()を呼び出す必要がありますか?

これは、理論的な部分と実際的な部分の2つの質問です。

Dictをサブクラス化する場合:

class ImageDB(dict):
    def __init__(self, directory):
        dict.__init__(self)  # Necessary?? 
        ...

dict.__init__(self)は、「安全」対策と同じように呼び出す必要がありますか(たとえば、重要な実装の詳細が重要な場合)? dict.__init__()notと呼ばれる場合、Pythonの将来のバージョンでコードが壊れるリスクはありますか?私はここで、いずれかのことを行う根本的な理由を探します(実際には、dict.__init__()を呼び出すのが安全です)。

私の推測では、ImageDB.__init__(self, directory)が呼び出されたとき、selfはすでに新しい空のdictオブジェクトであるため、dict.__init__を呼び出す必要はありません(最初はdictを空にしたい)。これは正しいです?

編集

上記の基本的な質問の背後にあるより実用的な質問は次のとおりです。私は(db.contents […]を常に実行する代わりに)db […]構文を頻繁に使用するため、dictをサブクラス化することを考えていました。オブジェクトの唯一のデータ(属性)は、実際には実際にはdictです。データベースにいくつかのメソッド(たとえば、get_image_by_name()get_image_by_code()など)を追加し、__init__()のみをオーバーライドしたいのは画像データベースだからですそれを含むディレクトリによって定義されます。

要約、(実用的な)質問は次のようになります:初期化が異なる(ディレクトリ名のみを取る)ことを除いて、辞書のように動作するものの適切な実装は何ですか?追加の方法?

多くの回答で「工場」が取り上げられました。つまり、dictをサブクラス化し、__init__()をオーバーライドしてメソッドを追加するのか、それともdictを返す(ファクトリ)関数を記述してメソッドを追加するのか、ということになると思います。ファクトリ関数は、追加のセマンティクスとメソッドがあることをタイプが示さないオブジェクトを返すため、最初のソリューションを好む傾向がありますが、どう思いますか?

編集2

新しいクラスが「辞書ではない」場合、特にその__init__メソッドがdictの__init__と同じ引数をとることができない場合(「実用的な」の場合)、dictをサブクラス化することはお勧めできません。上記の質問」)。言い換えれば、私が正しく理解していれば、コンセンサスは次のように思われます。サブクラス化する場合、すべてのメソッド(初期化を含む)は基本クラスのメソッドと同じ署名を持っている必要があります。これにより、isinstance(subclass_instance、dict)は、たとえばsubclass_instance.__init__()dict.__init__()のように使用できることを保証できます。

次に、別の実用的な質問が表示されます。初期化メソッドを除いて、dictと同じようなクラスをどのように実装する必要がありますか?サブクラス化せずに?これには、面倒な定型コードが必要になりますね。

32
Eric O Lebigot

サブクラス化するときは、おそらくdict.__init__(self)を呼び出す必要があります。実際、dictで何が起こっているのか正確にはわかりません(組み込みであるため)。これは、バージョンや実装によって異なる場合があります。 dictが内部データ構造を保持している場所がわからないため、これを呼び出さないと、不適切な動作が発生する可能性があります。

ちなみに、あなたはやりたいことを教えてくれませんでした。 dict(マッピング)動作を備えたクラスが必要で、実際にはdictが必要ない場合(たとえば、ソフトウェアのどこにもisinstance(x, dict)を実行するコードがない場合)、おそらくより良いでしょう。 UserDict.UserDictまたはUserDict.DictMixinを使用している場合はオフpython <= 2.5、または使用している場合はcollections.MutableMapping python> = 2.6。これらは、クラスに優れたdict動作を提供します。

編集:私はあなたがdictのメソッドのいずれもオーバーライドしていないという別のコメントを読みました!それなら、サブクラス化する意味はまったくありません。そうしないでください。

def createImageDb(directory):
    d = {}
    # do something to fill in the dict
    return d

編集2:dictから継承して新しいメソッドを追加したいが、オーバーライドする必要はありません。良い選択よりも:

class MyContainer(dict):
    def newmethod1(self, args):
        pass

    def newmethod2(self, args2):
        pass


def createImageDb(directory):
    d = MyContainer()
    # fill the container
    return d

ちなみに、どのメソッドを追加していますか?優れた抽象化を作成していると確信していますか?必要なメソッドを定義するクラスを使用し、その内部で「通常の」dictを使用する方がよいかもしれません。

ファクトリ関数: http://en.wikipedia.org/wiki/Factory_method_pattern

これは、コンストラクターをオーバーライド/変更するのではなく、インスタンスの構築を関数に委任する方法にすぎません。

15
Alan Franzoni

通常、基本クラス '__init__を呼び出す必要があるのに、なぜここで例外を作成するのですか?

__init__をオーバーライドしないか、__init__をオーバーライドする必要がある場合は基本クラス__init__を呼び出します。引数が心配な場合は、* args、** kwargsを渡すか、空のdictが必要な場合は何も渡しません。

class MyDict(dict):
    def __init__(self, *args, **kwargs ):
        myparam = kwargs.pop('myparam', '')
        dict.__init__(self, *args, **kwargs )

基本クラスが何をしているか、何をしていないかを想定するべきではありません。基本クラスを呼び出さないのは間違っています__init__

12
Anurag Uniyal

Dictをサブクラス化するときはピクルスに注意してください。たとえば、これには2.7では__getnewargs__が必要であり、古いバージョンでは__getstate____setstate__が必要です。 (理由はわかりません。)

class Dotdict( dict ):
    """ d.key == d["key"] """

    def __init__(self, *args, **kwargs):
        dict.__init__( self, *args, **kwargs )
        self.__dict__ = self

    def __getnewargs__(self):  # for cPickle.dump( d, file, protocol=-1)
        return Tuple(self)
3
denis

PEP 372 コレクションモジュールに順序付けられたdictを追加することを扱います。

「dictのサブクラス化は重要なタスクであり、多くの実装はすべてのメソッドを適切にオーバーライドしないため、予期しない結果が生じる可能性がある」と警告しています。

Python3.1に提案された(そして受け入れられた) patch は、次のような___init___を使用します。

_+class OrderedDict(dict, MutableMapping):
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        if not hasattr(self, '_keys'):
+            self._keys = []
+        self.update(*args, **kwds)
_

これに基づくと、dict.__init__()を呼び出す必要はないようです。

編集:dictのメソッドをオーバーライドまたは拡張していない場合は、AlanFranzoniに同意します。むしろdictファクトリを使用してください。サブクラス化より:

_def makeImageDB(*args,**kwargs):
   d = {}
   # modify d
   return d
_
2
unutbu

dict基本タイプのようなものをサブクラス化することを計画している場合は、コレクションから UserDict を検討することもできます。 UserDictはサブクラス化されるように設計されています。

0
prosti