辞書とオブジェクト - どちらがより効率的ですか? その理由は? 質問する

辞書とオブジェクト - どちらがより効率的ですか? その理由は? 質問する

メモリ使用量と CPU 消費の観点から、Python では辞書とオブジェクトのどちらがより効率的でしょうか?

背景:膨大な量のデータを Python にロードする必要があります。フィールド コンテナーだけのオブジェクトを作成しました。400 万個のインスタンスを作成し、それらを辞書に格納するのに約 10 分かかり、メモリは約 6 GB 消費されました。辞書の準備ができたら、それにアクセスするのは一瞬です。

例:パフォーマンスを確認するために、同じことを実行する 2 つの簡単なプログラムを作成しました。1 つはオブジェクトを使用し、もう 1 つは辞書を使用しています。

オブジェクト(実行時間約18秒):

class Obj(object):
  def __init__(self, i):
    self.i = i
    self.l = []
all = {}
for i in range(1000000):
  all[i] = Obj(i)

辞書(実行時間約12秒):

all = {}
for i in range(1000000):
  o = {}
  o['i'] = i
  o['l'] = []
  all[i] = o

質問:私が何か間違っているのでしょうか、それとも辞書の方がオブジェクトよりも速いだけでしょうか? 実際に辞書のパフォーマンスが優れているのであれば、その理由を誰か説明してもらえますか?

ベストアンサー1

使ってみましたか__slots__

からドキュメンテーション:

デフォルトでは、古いスタイルと新しいスタイルの両方のクラスのインスタンスには、属性を格納するための辞書があります。これにより、インスタンス変数が非常に少ないオブジェクトのスペースが無駄になります。大量のインスタンスを作成すると、スペースの消費が深刻になる可能性があります。

デフォルトは、__slots__新しいスタイルのクラス定義で定義することでオーバーライドできます。宣言はインスタンス変数のシーケンスを受け取り、各インスタンスに各変数の値を保持するのに十分なスペースを予約します。インスタンスごとには作成されない__slots__ため、スペースが節約されます。__dict__

それで、メモリだけでなく時間も節約できるのでしょうか?

私のコンピューターで 3 つのアプローチを比較します。

test_slots.py:

class Obj(object):
  __slots__ = ('i', 'l')
  def __init__(self, i):
    self.i = i
    self.l = []
all = {}
for i in range(1000000):
  all[i] = Obj(i)

テストオブジェクト:

class Obj(object):
  def __init__(self, i):
    self.i = i
    self.l = []
all = {}
for i in range(1000000):
  all[i] = Obj(i)

テスト辞書:

all = {}
for i in range(1000000):
  o = {}
  o['i'] = i
  o['l'] = []
  all[i] = o

test_namedtuple.py (2.6 でサポート):

import collections

Obj = collections.namedtuple('Obj', 'i l')

all = {}
for i in range(1000000):
  all[i] = Obj(i, [])

ベンチマークを実行します(CPython 2.5 を使用):

$ lshw | grep product | head -n 1
          product: Intel(R) Pentium(R) M processor 1.60GHz
$ python --version
Python 2.5
$ time python test_obj.py && time python test_dict.py && time python test_slots.py 

real    0m27.398s (using 'normal' object)
real    0m16.747s (using __dict__)
real    0m11.777s (using __slots__)

名前付きタプルテストを含む CPython 2.6.2 を使用します。

$ python --version
Python 2.6.2
$ time python test_obj.py && time python test_dict.py && time python test_slots.py && time python test_namedtuple.py 

real    0m27.197s (using 'normal' object)
real    0m17.657s (using __dict__)
real    0m12.249s (using __slots__)
real    0m12.262s (using namedtuple)

はい、(驚くことではありませんが) を使用すると__slots__パフォーマンスが最適化されます。名前付きタプルを使用すると、 と同様のパフォーマンスが得られます__slots__

おすすめ記事