0

Python の複数のノードでシステム上で多くのコマンドを実行する必要があります。各ノードを独立して実行したいので、ノードごとにクラスを作成し、ノードに固有のメソッドで埋めることにしました。しかし、これらのメソッドを利用するアルゴリズムを作成するとき、すべての呼び出しを for ループに入れなければならないことがわかりました。

class MultipleThings(object):
    def __init__(self, index):
        self.index = index

    def some_function(self):
        print "I am index ", self.index

class CollectionOfThings(object):
    def __init__(self):
        self.list_of_objects = []
        for index in range(5):
            self.list_of_objects.append(MultipleThings(index))

        for thing in self.list_of_objects:     # Yuck!!
            thing.some_function()

main = CollectionOfThings()

このコードは完全に機能し、5 つの print ステートメントが表示されます。しかし、それは醜くて退屈です。「self.list_of_objects: の for もの」を削除して、self.some_function() を 1 回だけ呼び出すにはどうすればよいですか?

編集:これを「バッチ」モードと見なすことができると思いますか?たとえば、10 台のシステムで「ls -l」を実行し、各クラス インスタンスにそれらのコマンドを処理させたいとします。それらがすべて完了したら、次のコマンドは 10 のシステムすべてで「rm tmp」を実行することなどです。各ノードで for ループがブロックされないように、マルチプロセッシングも必要になります。

4

2 に答える 2

0

これがあなたが望むかどうかわからない:

class CollectionOfThings(object):
    def __init__(self):
        self.list_of_objects = []
        self.list_of_objects = [MultipleThings(index) for index in range(5)]
        self.callFunc(self.list_of_objects, "some_function")

    def callFunc(self, items, func, *args, **kwargs):
        for thing in items:
            getattr(thing, func)(*args, **kwargs)

@Thorsten が指摘しているように、単純mapに a を使用することlambdaは、あなたがやろうとしていることを実行する方法です。私の試みは、一般的な解決策を作ることでした。

文字列引数を渡さないように、関数自体をそのように渡すことができます。

class CollectionOfThings(object):
    def __init__(self):
        self.list_of_objects = []
        self.list_of_objects = [MultipleThings(index) for index in range(5)]
        self.callFunc(self.list_of_objects, MultipleThings.some_function)

    def callFunc(self, items, func, *args, **kwargs):
        for thing in items:
            func(thing, *args, **kwargs)

これは、リストと辞書の両方を返します。

class MultipleThings(object):
    def __init__(self, index):
        self.index = index

    def some_function(self, key, value):
        return "I am index %s with key %s and value %s" % (self.index, key, value)

class CollectionOfThings(object):
    def __init__(self):
        self.list_of_objects = []
        self.list_of_objects = [MultipleThings(index) for index in range(5)]
        retList, retDict = self.callFunc(self.list_of_objects, MultipleThings.some_function, "foo", value="bar")
        print retList, retDict

    def callFunc(self, items, func, *args, **kwargs):
        retList = []
        retDict = {}
        for i, thing in enumerate(items):
            funcReturn = func(thing, *args, **kwargs)
            retList.append(funcReturn)
            retDict[i] = funcReturn

        return retList, retDict
于 2013-01-04T08:05:37.737 に答える
0

listたとえば、10 個のアイテムがあり、 の各アイテムに対して 50 個の関数を実行したいのに、50 個のループlistを記述する必要はないように思えます。for

1 つの可能性は、それをラップする関数を作成することです。

def apply(method, seq):
    for item in seq:
        method(item)

次に、これの代わりに:

for thing in self.list_of_objects:     # Yuck!!
    thing.some_function()
for thing in self.list_of_objects:     # Yuck!!
    thing.other_function()
for thing in self.list_of_objects:     # Yuck!!
    thing.third_function()
# ... 47 more times

あなたはこれを行うことができます:

apply(ThingClass.some_function, self.list_of_objects)
apply(ThingClass.other_function, self.list_of_objects)
apply(ThingClass.third_function, self.list_of_objects)
# ... 47 more times

関数とメソッドは、他のものと同様に、Python のファーストクラス オブジェクトであるため、他の関数に簡単に渡すことができます。もちろんfirst_thing.some_function、 とsecond_thing.some_functionは実際には異なるバインドされたメソッドです。selfトリックは、クラスからバインドされていないメソッドを取得し、明示的なパラメーターとしてオブジェクトを渡すことができるということです。first_thing.some_function( 、ThingClass.some_functiontype(first_thing.some_function)、および を印刷してtype(ThingClass.some_function)、対話型インタープリターで操作してみてください。)

もちろん、これは、これらすべてのアイテムが同じメソッドを持っている理由は、それらが同じクラスのインスタンスであるためだと仮定しています。それが正しくなく、代わりにダック タイピングに依存している場合は、少し異なるものが必要です。

def apply(methodname, seq):
    for item in seq:
        getattr(item, methodname)()

apply('some_function', self.list_of_objects)
# ... 49 more times

ここでのトリックは、getattr実行時に任意のメソッドまたはメンバーを名前で取得できる関数です。

しかし、よく考えてみると、ここで本当に必要なのは、これら 50 個のバインドされていないメソッドまたは名前を反復処理することであり、同じことをまったく繰り返す必要はありません。例えば:

for name in ('some_function', 'other_function', 'third_function',
             # ... 47 more names
            ):
    for obj in self.list_of_objects:
        getattr(obj, name)()

メソッドの最初のバージョンはapply、ビルトインmap(Python 2.x のみで、3.x ではなく) またはリスト内包表記で簡単に置き換えることができることに注意してください。ただし、そうしない理由がいくつかあります。

  • map一般に、副作用のために関数を呼び出すだけの場合、使用するスタイルや理解が疑わしいと見なされます。
  • 50*10 だけではなく、多数のアイテムがある場合list、必要のない結果を構築するためにメモリと時間が無駄になります。
  • Python 3 では、mapの代わりにイテレータを返すlistため、何らかの方法で反復しない限り、実際には関数をまったく実行しません。(あなたのprint発言から、あなたは明らかに 2.x を使用していますが、いずれ 3.x に切り替えることになるでしょう。)

これらの問題は、(またはリスト内包itertools.imap表記) の代わりに (またはジェネレーター式) を使用mapし、たとえば 0 サイズのdeque. しかし、その時点では、コードが何をしているのか正確にはわかりません。

一方、関数を明示的に記述するということは、必要に応じて、たとえば 2 番目のバージョンに簡単に変更できることを意味します。

于 2013-01-04T08:33:15.390 に答える