2016-11-14 4 views
0

私は、インスタンス属性の固定セット(メタ属性と呼ぶ)と他のインスタンス属性の任意のセットを区別できるクラスを実装しました。カスタム__getattr__と__setattr__を使ったPythonディープコピー

それはカスタム__getattr____setattr__あります

class MyClass(object): 

    def __init__(self, meta1, meta2, **other_attr): 
     super(MyClass, self).__setattr__('meta1', meta1) 
     super(MyClass, self).__setattr__('meta2', meta2) 
     super(MyClass, self).__setattr__('params', {}) 

     self.params = {key: other_attr[key] for key in other_attr} 


    # this is called when default lookup finds nothing 
    def __getattr__(self, key): 
     print('__getattr__({})'.format(key)) 
     try: 
      return self.params[key] 
     except KeyError: 
      raise AttributeError(key) 


    # this is called always 
    def __setattr__(self, key, value): 
     print('__setattr__({}, {})'.format(key, value)) 
     if key in self.__dict__: 
      super(MyClass, self).__setattr__(key, value) 
     else: 
      self.params[key] = value 

これは正常に動作し、他のすべての属性がparams辞書に行っている間、すべてのメタ属性は、インスタンスの__dict__に直接移動:

obj1 = MyClass(meta1 = 'foo', meta2 = 'bar', x=1, y=2, z=3) 
obj1.w = 4 
print(obj1.__dict__) 

出力:

__setattr__(params, {'y': 2, 'x': 1, 'z': 3}) 
__setattr__(w, 4) 
{'meta1': 'foo', 'meta2': 'bar', 'params': {'y': 2, 'x': 1, 'z': 3, 'w': 4}} 

を除き、私は私のオブジェクトをdeepcopyしようとすると、それは奇妙な何かを行います。

import copy 
obj1 = MyClass(meta1='foo', meta2='bar', x=1, y=2, z=3) 
obj2 = copy.deepcopy(obj1) 

出力:最後に

__setattr__(params, {'y': 2, 'x': 1, 'z': 3}) 
__getattr__(__deepcopy__) 
__getattr__(__getnewargs__) 
__getattr__(__getstate__) 
__getattr__(__setstate__) 
__getattr__(params) 
__getattr__(params) 
__getattr__(params) 
__getattr__(params) 
__getattr__(params) 
__getattr__(params) 
__getattr__(params) 
__getattr__(params) 
... 
and then it calls __getattr__ about a hundred more times 

をそれはコピーを作成しますが、なぜんそれは__getattr__に非常に多くの呼び出しを行いますか?これは、再帰検索を引き起こしている

答えて

2

obj2__init__経由で初期化されていない覚えている)

return self.params[key] 

代わりに働いていたこの

return super().__getattribute__('params')[key] 
+0

おかげで、行う必要があります。しかし、なぜそれが*無限*再帰を引き起こさないのですが、ある時点で停止しますか? – spiderface

+0

@spiderface、 'RuntimeError:Pythonオブジェクトを呼び出す際に最大再帰深度を超過しました。 'おそらくあなたは若干異なる例外ハンドラを持つバージョンを試しました –

+0

それは変です。また、私は '__getattribute__'の値を返す必要がないことも知っていました。単にそれを呼び出して' return self.params [key] 'を返すだけで十分です。 – spiderface

関連する問題