オブジェクトもどきが成長してきた。
良いか悪いか微妙。
目的
foo.bar.baz = 10
を返すようなオブジェクトを手軽に作ること。
新しく追加
ほとんど同様(でも一部異なる)なオブジェクトを作りたくなった。テストのダミーとかで。
それをするために、almost_cloneという関数を書いた。
O = ObjectLike oo = O(x=O(y=2)) eq_(oo.x.y, 2) eq_almost_clone(oo, x__y=10).x.y, 10) eq_(oo.x.y, 2)
この時、copy.copyを使ったらshallow copyだったのでdeepcopyを使った。
__deepcopy__を定義しなければ使えなかった。
似たようなオブジェクトを作る。
foo__bar__bazという感じで引数を渡してあげると、それに対応した値に変更される。
例えば、a.b.c.d.eのeの値だけを変えたオブジェクトを作りたい場合には(e=10に変更)
almost_clone(a, b__c__d__e=10)
という風に渡す。内部でコピーを作っているので、元のオブジェクト(a)の持つ値は変わらない。
だんだん長くなる。
from copy import deepcopy, copy class ObjectLike(dict): __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ def __deepcopy__(self, memo): obj = O() for k, v in self.items(): if hasattr(v, "__deepcopy__"): obj[k] = deepcopy(v, memo) else: obj[k] = v return obj O = ObjectLike def almost_clone(obj, **kwargs): """ oo = O(x=O(y=2)) self.assertEqual(oo.x.y, 2) self.assertEqual(almost_clone(oo, x__y=10).x.y, 10) self.assertEqual(oo.x.y, 2) """ def pair_to_accessor(target, k, v): tokens = k.split("__") if len(tokens) > 1: for token in tokens[0:-1]: target = target[token] last_token = tokens[-1] target[last_token] = v duped = deepcopy(obj) for k,v in kwargs.items(): pair_to_accessor(duped, k, v) return duped