2016-05-03 27 views
1

私は2つのメンバーを持つクラスを持っています - m1は文字列、m2は辞書です。Python - 名前に基づいてクラスメンバーをリセットする方法

myA.m2.reset()をself.m2.clear()と同じように呼び出してm2をリセットします。 self.m1 = Noneと等価にmyA.m1.reset()を呼び出してm1をリセットします。

クラスAでこのリセットメソッドを実装するにはどうすればよいですか?

class A(object): 
    def __init__(self): 
     self.m1 = None 
     self.m2 = {} 

    def reset(self): 
     """ 
     if it is m2: self.m2.clear() 
     elif it is m1: self.m1 = None 
     """ 

myA = A() 
myA.m2[1] = 2 

答えて

1

編集:私は非常に申し訳ないOP - 記述子を使用する私の提案は良いアイデアのように思えたが、堅牢な方法でmyA.m2.reset()のようなコードを書くことができますするつもりされていません。

私はあなたのアイデアを提供するために、この回答を参考にしておきます。


これはpython descriptorsの仕事です!それはメンバーの(Iは緩くその言葉を使う)

myA.some_member.reset() 

...とどのような「種類」に応じて、カスタム動作を持っている:私は理解していれば

は、あなたがこのような何かを行うことができるようにしたいです。

class ResettableDict(dict): 
    def reset(self): 
     self.clear() 

class A(object): 
    def __init__(self): 
    self.m2 = ResettableDict() 

あなたに実行しようとしている問題は、しかし、文字列は不変であるので、あなたは、strをサブクラス化することにより、同様の何かを行うことができないということである(すなわち:あなたは、この辞書のようなm2メンバーにうまく働いて得ることができます彼らはdictのように "クリア"することはできません)。さらに、代入演算子を使用してResettableStringメンバーに値を渡すと、ResettableStringになります。例:

class ResettableString(str): 
    pass # Just a placeholder for this example 

がテスト:

>>> myA = A() 
>>> myA.m2[1] = 2 
>>> type(myA.m2) 
<class '__main__.ResettableDict'> # works! 
>>> myA.m1 = 'string!' 
>>> type(myA.m2) 
<class 'str'> # no longer a ResettableString! DOH!!! 

Pythonはほとんどの演算子を "オーバーロード" する機能があります。しかし、一般的に=(代入)演算子にオーバーロードするクラスを書くことはできません。何をすべきか?

答え:私が最初に言ったように、記述子!我々はResettableと呼ばれる記述子を作るつもりです。 Resettableは、reset()メソッドを使用して、メンバーの値をデフォルト値に戻します。

あなたはこのようにそれを使用します:ここで

class A(object): 
    m1 = Resettable('m1', None) 
    m2 = Resettable('m2', {}) 

Resettable次のとおりです。

class Resettable(object): 
    '''A class descriptor that can be reset to its default value.''' 
    def __init__(self, name, default): 
     self.default = default 
    def reset(self): 
     setattr(self.current_instance, self.name, self.default) 
     del self.current_instance 
    def __get__(self, obj, typ): 
     try: 
      return getattr(obj, '_%s' % self.name) 
     except AttributeError: 
      setattr(obj, self.name, self.default) 
      return self.default 
     finally: 
      self.current_instance = obj 
    def __set__(self, obj, value): 
     setattr(obj, '_%s' % self.name, value) 

A Pythonの記述は、多くの機能を提供します。それらのうちの1つは、=(代入)演算子(__set__メソッド経由、このメソッドはオプトイナイン)と.( "get")演算子(__get__メソッド経由)の両方の「オーバーロード」です。

オブジェクトメンバーに値を割り当てると、デフォルトのPythonのgetおよびsetの動作は、ディスクリプタオブジェクトによって提供される動作によって上書きされます。

>>> myA = A() 
>>> myA.m2[1] = 2 
>>> type(A.m2) 
<class '__main__.Resettable'> # works! 
>>> myA.m1 = 'string!' 
>>> type(A.m1) 
<class '__main__.Resettable'> # works!!!!! 
>>> myA.m2.reset() 
>>> myA.m1.reset() 
+0

このページを指摘していただきありがとうございます。しかし、m1/m2は、インスタンスmyAがクラスAではないことを意図しています。 –

+0

@ Lazysheep.wang記述子がクラス 'A'オブジェクトメンバであり、インスタンスmyAオブジェクトメンバではないことは事実です。しかし、[descriptor protocol](http://python-reference.readthedocs.io/en/latest/docs/dunderdsc/)は、インスタンスメンバルックアップが開始されると、クラスレベルのメンバ記述子が存在する場合にそれが返されることを意味します。 –

+0

リックありがとうございます。それは素晴らしい解決策です。実際には、このAクラスで少なくとも10人のメンバーを定義し、さらに追加していくことがあります。私は明日あなたのソリューションに自分のソリューションを組み込み、それに対応してこのスレッドを更新しようとします。そのような詳細であなたのソリューションをお寄せいただきありがとうございます! –

0

M1、M2はその含むクラスの機能にクラスカントコールのit.Theメンバーのクラスではないインスタンスのメンバーで、メンバーはそのインスタンス内の関数を呼び出すことができます。 sinpler文脈では、m1はmyA.reset()を呼び出すべきではありません。myA.m1.clear()を呼び出すことができます。それをリセットするには、どの変数をクリアするかをクラスに伝える引数を渡す必要があります。

+0

私はそれがまさに私がやりたいことだと思います。 "あなたは、どの変数をクリアするかをクラスに伝える引数を渡すことができます。"このメソッドを実装する方法を提案できますか?メンバー名を比較し、別のリセット操作をしたい。 –

0

これは、私が他の答えで放棄したディスクリプタベースのソリューションでは期待していなかったほどエレガントではありませんが、これが私の考え方です。

class Resettable(object): 
    '''A class with "resettable" fields.''' 
    _resettables = {} 
    def __init__(self): 
     for field, value in self._resettables.items(): 
      setattr(self, field, value) 
    def reset(self, field): 
     try: 
      setattr(self, field, self._resettables[field]) 
     except KeyError: 
      raise AttributeError('%s is not a resettable field' % field) 

class A(Resettable): 
    _resettables= dict(m1 = None, m2 = {}) 

テスト:

>>> myA.m1 = 'string' 
>>> myA.reset('m1') 
>>> assert myA.m1 is None 

代わりのreset方法で力仕事をやって、あなたは完全に異なるアプローチを使用して__getattr__方法を使用してデフォルト値を使用してフィールドのいずれかの値を返すことができます。

class Resettable(object): 
    '''A class with "resettable" fields.''' 
    _resettables= {} 
    def __init__(self): 
     for field, value in self._resettables.items(): 
      setattr(self, field, value) 
    def __getattr__(self, attr): 
     try: 
      return self._resettables[attr] 
     except KeyError: 
      pass 
    def reset(self, field): 
     if field not in self._resettables: 
      raise AttributeError('%s is not a resettable field' % field) 
     else: 
      try: 
       delattr(self, field) 
      except AttributeError: 
       pass 

class A(Resettable): 
    _resettables= dict(m1 = None, m2 = {}) 
関連する問題