Pythonでクラスインスタンスのコピーを作成したいと思います。私は試した copy.deepcopy
しかし、エラーメッセージが表示されます。
RuntimeError:現時点では、ユーザーが明示的に作成した変数(グラフから離れる)のみがディープコピープロトコルをサポートしています
だから私は次のようなものがあると仮定します:
class C(object):
def __init__(self,a,b, **kwargs):
self.a=a
self.b=b
for x, v in kwargs.items():
setattr(self, x, v)
c = C(4,5,'r'=2)
c.a = 11
del c.b
そして今、c
の同一のディープコピーを作成したいのですが、簡単な方法はありますか?
私はほとんどそれを理解しました。私が克服できない唯一の問題は、すべてのクラスの初期化引数の許容セット(__init__
の引数)を知ることです。したがって、次の2つの仮定をする必要があります。
1)C
と呼ぶクラスargsC
の一連のデフォルト引数があります。 2)C
のすべてのオブジェクトは、空の引数で初期化できます。
その場合、私は最初:C
をコピーしたいインスタンスからc
クラスの新しいインスタンスを初期化します:
c_copy = c.__class__(**argsC)
2番目:c
のすべての属性を調べ、c_copy
属性をc
の属性のコピーに設定します
for att in c.__dict__:
setattr(c_copy, att, object_copy(getattr(c,att)))
ここで、object_copy
は、作成中の関数の再帰的なアプリケーションです。
最後:c_copy
のすべての属性を削除しますが、c
の属性は削除しません:
for att in c_copy.__dict__:
if not hasattr(c, att):
delattr(c_copy, att)
これをすべてまとめると、次のようになります。
import copy
def object_copy(instance, init_args=None):
if init_args:
new_obj = instance.__class__(**init_args)
else:
new_obj = instance.__class__()
if hasattr(instance, '__dict__'):
for k in instance.__dict__ :
try:
attr_copy = copy.deepcopy(getattr(instance, k))
except Exception as e:
attr_copy = object_copy(getattr(instance, k))
setattr(new_obj, k, attr_copy)
new_attrs = list(new_obj.__dict__.keys())
for k in new_attrs:
if not hasattr(instance, k):
delattr(new_obj, k)
return new_obj
else:
return instance
したがって、すべてをまとめると次のようになります。
argsC = {'a':1, 'b':1}
c = C(4,5,r=[[1],2,3])
c.a = 11
del c.b
c_copy = object_copy(c, argsC)
c.__dict__
{'a':11、 'r':[[1]、2、3]}
c_copy.__dict__
{'a':11、 'r':[[1]、2、3]}
c.__dict__
{'a':11、 'r':[[1、33]、2、3]}
c_copy.__dict__
{'a':11、 'r':[[1]、2、3]}
これが望ましい結果です。可能であればdeepcopy
を使用しますが、例外が発生する場合は、それを使用せずに実行できます。
それを行う1つの方法は、__copy__
はC
クラスで次のようになります。
class A:
def __init__(self):
self.var1 = 1
self.var2 = 2
self.var3 = 3
class C(A):
def __init__(self, a=None, b=None, **kwargs):
super().__init__()
self.a = a
self.b = b
for x, v in kwargs.items():
setattr(self, x, v)
def __copy__(self):
self.normalizeArgs()
return C(self.a, self.b, kwargs=self.kwargs)
# THIS IS AN ADDITIONAL GATE-KEEPING METHOD TO ENSURE
# THAT EVEN WHEN PROPERTIES ARE DELETED, CLONED OBJECTS
# STILL GETS DEFAULT VALUES (NONE, IN THIS CASE)
def normalizeArgs(self):
if not hasattr(self, "a"):
self.a = None
if not hasattr(self, "b"):
self.b = None
if not hasattr(self, "kwargs"):
self.kwargs = {}
cMain = C(a=4, b=5, kwargs={'r':2})
del cMain.b
cClone = cMain.__copy__()
cMain.a = 11
del cClone.b
cClone2 = cClone.__copy__()
print(vars(cMain))
print(vars(cClone))
print(vars(cClone2))
はい、deepcopyを使用してクラスインスタンスのコピーを作成できます。
from copy import deepcopy
c = C(4,5,'r'=2)
d = deepcopy(c)
これにより、クラスインスタンス 'c'のコピーが 'd'に作成されます。