2016-05-30 13 views
3

クラスのいくつかのメソッドに対して同じ編集を行う簡単な方法があるかどうかを知りたいと思います。例:クラスのいくつかのメソッドをループで上書きする

class Dog(): 
    def __init__(self): 
     self.name = 'abc' 
     self.age = 1 

    def setName(self, newValue): 
     self.name = newValue 

    def setAge(self, newValue): 
     self.age = newValue 

class TalkingDog(Dog): 

    def __init__(self): 
     super().__init__() 
     # The end is in pseudo code : 
     for method in TalkingDog.allMethods : 
      method = method + 'print('I have been edited !')' 

だから私はこれを試してみました

...私はまた、各メソッドを上書きすることができることを知っているが、メソッドの数十の状況では、それは少し退屈になります。

class TalkingDog(Dog): 

    def __init__(self): 
     super().__init__() 
     for method in self.__dir__(): 
      if method.startswith('set'): 
       oldMethod = getattr(self, method) 
       def _newMethod(newValue): 
        oldMethod(newValue) 
        print('I have been edited !') 
       setattr(self, method, _newMethod) 


a = TalkingDog() 
print(a.setName) >>> <function TalkingDog.__init__.<locals>._newMethod at 0x0000000002C350D0> 

これはほとんど動作しますが、setNameはもうメソッドではありません。関数を含む属性です。なぜ私は完全に理解しますが、私はよりクリーンな結果を得ようとしています。その結果、後で問題が発生する危険性があります。たとえば、ライブラリピックルをそのオブジェクトに使用することはできません(エラーは_pickle.PicklingError: Can't pickle <function TalkingDog.__init__.<locals>._newMethod at 0x00000000003DCBF8>: attribute lookup _newMethod on __main__ failedです)。

+2

'set'や' get'メソッドではなく、プロパティを使う:http://stackoverflow.com/q/1554546/3001761 – jonrsharpe

+1

また、実際のユースケースは?あなたは本当に話す犬を作っていますか?もしそうなら、犬は年齢が変わるたびに話すべきではありません。犬に話をしたい場合は、年齢を変えることとは別に話す。 –

+0

@jonrsharpe私はなぜ、どのようにプロパティを使用してその場合に役立つか分かりません。 – Morgan

答えて

2

これを行うにはPython的な方法は、プロパティを使用するものもあるdescriptor protocolを、使用することが考えられます:

class VocalAttribute: 

    def __init__(self, name, feedback): 
     """Called when you first create the descriptor.""" 
     self.name = name # the name of the attribute 'behind' the property 
     self.feedback = feedback # the feedback to show when the value changes 

    def __get__(self, obj): 
     """Called when you get the descriptor value.""" 
     return getattr(obj, self.name) 

    def __set__(self, obj, value): 
     """Called when you set the descriptor value.""" 
     prev = getattr(obj, self.name, None) 
     if value != prev: 
      setattr(obj, self.name, value) 
      print(self.feedback) 

    def __delete__(self, obj): 
     """Called when you delete the descriptor value.""" 
     delattr(obj, self.name) 


class Foo: 

    bar = VocalAttribute('_bar', 'I have been edited!') 


foo = Foo() 

print('1.') 

foo.bar = 'hello' 

print('2.') 

foo.bar = 'hello' 

print('3.') 

foo.bar = 'world' 

出力:これが唯一の新しい価値のフィードバックを与えることを

1. 
I have been edited! 
2. 
3. 
I have been edited! 

注意古いものとは異なります - あなたは__set__の必要に応じて振る舞いを微調整することができます。また、(これは、Javaの何であるか?)ではなくゲッターとセッターを呼び出すために必要とするよりも、あなたが直接から読み込まれ、foo.barに割り当てることができることを意味し

+0

私は記述子protocalに慣れていません。私はもう少し詳しく読んで、自分のコードで試してみます。助けてくれてありがとう ! :) – Morgan

+0

これは正解です。 –

-1

をデコレータので、可能性があり、それを使用する方法ここに呼ばれる明示的な:

def updater(obj, call_back, call_back_args=(), call_back_kw=None, replace=False): 
    # ability to be called on the fly with different args and kw for the callback 
    # now it returns the updated obj (instance or class) 
    # but could a be factory returning a new obj in this case make a copy of obj, update this coy and return it 

    def update_function(fn, *args, **kw): 
     def wrapper(*args, **kw): 
      if replace: 
       # call only the callback 
       res = call_back(*call_back_args, **call_back_kw) 
      else: 
       res = fn(*args, **kw) 
       call_back(*call_back_args, **call_back_kw) 
      return res 
     return wrapper 

    # get all methods of the obj 
    # and apply update_function (a decorator) to all methods 
    for name, m in inspect.getmembers(
      obj, predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)): 
     # make the selection here 
     # could be made on the name for instance 
     if not name.startswith('_'): 
      new_m = update_function(m) 
      setattr(obj, name, new_m) 

    return obj 

# declare a callback 
def call_back(*args, **kw): 
    # simple callback 
    print("I have been edited and called with %r args and %r kw " % (args, kw)) 

a = Dog() 

# could be called on instance or class 
# apply the callback on all "public" methods 
updater(
    a, 
    call_back, 
    call_back_args=(2, 3, 4), 
    call_back_kw={"kw1": "v_1"} 
) 
+0

誰かが私にdownvoteを説明できますか? –

関連する問題