2017-06-12 1 views
2

編集:エッジケースについて考えると、それほど有用ではないようです。私はそれを興味深いと感じているので、これを開いたままにしておきますが、それは本当に良いことではないことを理解しています。クラスやオブジェクトの "マルチ"オブジェクトハンドラを持つ方法は?

特定のクラスのいくつかのオブジェクトを取得し、それらを結合して同じクラスの「マルチオブジェクト」にすると、基本的にはその子クラスの同じ属性が取得されます。私は、それを説明するかどうかはわかりませんので、ここでの例です:

#!/usr/bin/env python3 

class Foo: 
    def __init__(self, x): 
     self.x = x 

    def bar(self, y): 
     print(self.x) 
     return 2 * y 


f1 = Foo(2) 
f2 = Foo(3) 
f3 = Foo(5) 
f4 = Foo(7) 

def multi(*args): 
    if len(args) == 0: 
     raise ValueError("Requires at least one object") 
    if not all(isinstance(arg, type(args[0])) for arg in args): 
     raise TypeError("All objects must be the same type") 
    # ... magic 

multi_f = multi(f1, f2, f3, f4) 

assert multi_f.x == [2, 3, 5, 7] # attributes return a list of each of the objects in the multi_f 
assert multi_f.bar(y=5) == [10, 10, 10, 10] # prints 2 then 3 then 5 then 7 but "5" is passed to all of them 

があった場合、私が最初にかかわらず__getattr__や友人をオーバーライドするが、他の機能のすべての思考、あなたがオーバーライドし、疑問に思っ必要があるだろうより良い方法。

バー機能のための別の方法としては、各機能は、それが自身のパラメータですが、これらは相互に排他的であるになるだろうようにすることができます。

assert multi_f.bar([ 
    [[], dict(y=5)], 
    [[], dict(y=10)], 
    [[], dict(y=20)], 
    [[], dict(y=40)], 
]) == [10, 20, 40, 80] 

このアイデアでは、しかし、あなたはリストをスプラットする必要があると思いますし、各オブジェクトの関数呼び出しを記述します。

答えて

1

これは楽しいアイデアです!したがって、以下のこのソリューションはクラス(Multi)を使用しています(オブジェクトを作成していますので、、実際のオブジェクトである必要があります)。私は__getattr__を実装しましたが、を実装しました。は、必要に応じて他のメソッドをオーバーライドする必要があります(例えば、割り当てたい場合は__setattr__、等価性をテストする場合は__eq__など)。どのように行動すべきかを正確に決める計画!

class Multi: 
    def __init__(self, *args): 
     self.foos = args 

    def __getattr__(self, key, *args, **kwargs): 
     ret = [] 
     # two options - accessing values, or methods to call 
     # this boolean decides which type to return (i'm sure there's a neater way, but this was quick) 
     wrap = False 

     # build a list of the attributes from foos 
     for foo in self.foos: 
      x = getattr(foo, key) 
      if callable(x): 
       wrap = True 
      ret.append(x) 

     # return an anonymous function that when called, returns a list 
     # with the result of calling each callable with whatever args/kwargs 
     if wrap: 
      return lambda *args, **kwargs: [x(*args, **kwargs) for x in ret] 

     # otherwise just return the list of values 
     return ret 

multi_f = Multi(f1, f2, f3, f4) 
assert multi_f.x == [2, 3, 5, 7] # attributes return a list of each of the objects in the multi_f 
assert multi_f.bar(y=5) == [10, 10, 10, 10] # prints 2 then 3 then 5 then 7 but "5" is passed to all of them 

私はあなたが提案する最後のオプションが可能であると信じていますが、フラグ/トグルスイッチとして余分な引数を使用しない限り、ええ、彼らは両方を同時に実装することができませんでした。

+1

はい、私は同意します、これは私がやったことに似ていますが、私は 'type'を使って終わり、クラスをインラインで作成しました。しかし、これはよりきれいに見えます。お返事をありがとうございます! – Goodies

関連する問題