31

コレクションにはモデルが含まれ、モデルにはウィジェットが含まれるなど、ウィジェットのツリー構造があります。コレクション全体をコピーしたいのですcopy.deepcopyが、オブジェクトを「ピクルしてピクル解除」するよりも高速ですが、C で記述されている cPickle の方がはるかに高速です。

  1. deepcopy の代わりに常に cPickle を使用すべきではないのはなぜですか?
  2. 他のコピーの代替手段はありますか?pickle は deepcopy よりも遅いですが、cPickle は高速であるため、deepcopy の C 実装が勝者になる可能性があります。

サンプル テスト コード:

import copy
import pickle
import cPickle

class A(object): pass

d = {}
for i in range(1000):
    d[i] = A()

def copy1():
    return copy.deepcopy(d)

def copy2():
    return pickle.loads(pickle.dumps(d, -1))

def copy3():
    return cPickle.loads(cPickle.dumps(d, -1))

タイミング:

>python -m timeit -s "import c" "c.copy1()"
10 loops, best of 3: 46.3 msec per loop

>python -m timeit -s "import c" "c.copy2()"
10 loops, best of 3: 93.3 msec per loop

>python -m timeit -s "import c" "c.copy3()"
100 loops, best of 3: 17.1 msec per loop
4

5 に答える 5

35

問題は、pickle+unpickle の方が (C 実装で) 高速になる可能性があることです。これは、deepcopyほど一般的ではないためです。多くのオブジェクトをディープコピーできますが、pickle できません。たとえば、クラスAが次のように変更されたとします...:

class A(object):
  class B(object): pass
  def __init__(self): self.b = self.B()

copy1でも問題なく動作します (A の複雑さにより速度が低下しますが、停止することはありません)。copy2そしてcopy3休憩、スタックトレースの最後は言う...:

  File "./c.py", line 20, in copy3
    return cPickle.loads(cPickle.dumps(d, -1))
PicklingError: Can't pickle <class 'c.B'>: attribute lookup c.B failed

つまり、ピクルは常にクラスと関数がモジュールのトップレベルのエンティティであると想定しているため、それらを「名前で」ピクルします。ディープコピーはそのような仮定をまったく行いません。

したがって、「ある程度のディープコピー」の速度が絶対的に重要であり、ミリ秒単位が重要であり、かつ、複製するオブジェクトに適用されることがわかっている特別な制限を利用したい場合 (酸洗を作成するオブジェクトなど)適用可能なもの、またはシリアライゼーションやその他のショートカットの他の形式を支持するものは、ぜひ先に進んでください。将来のメンテナーのために明示的に。

一般性が必要な NORMAL の場合は、deepcopy!-)を使用します。

于 2009-09-11T14:27:53.363 に答える
7

コードが読みやすくなるため、deepcopy を使用する必要があります。シリアル化メカニズムを使用してメモリ内のオブジェクトをコピーすることは、コードを読んでいる別の開発者にとって少なくとも混乱を招きます。deepcopy を使用すると、deepcopy の将来の最適化のメリットを享受できることも意味します。

最適化の第 1 のルール: しない。

于 2009-09-11T13:18:11.707 に答える
1

そもそもコピーを避ける方が、さらに高速です。あなたはレンダリングを行っていると述べています。オブジェクトをコピーする必要があるのはなぜですか?

于 2009-09-11T14:41:01.557 に答える
1

短くてやや遅い:

  • とにかくオブジェクトをcPickleする必要がある場合は、cPickleメソッドを使用してディープコピー(ただしドキュメント)することもできます

たとえば、次のことを検討してください。

def mydeepcopy(obj):
    try:
       return cPickle.loads(cPickle.dumps(obj, -1))
    except PicklingError:
       return deepcopy(obj)
于 2013-09-28T09:54:24.813 に答える