2013-01-04 14 views
0

我需要在Python中的多個節點上的系統上運行許多命令。我希望每個節點都獨立運行,所以我想我會爲每個節點創建一個類,並用特定於節點的方法填充它。但是,寫我的算法時利用這些方法,我發現我已經把每個呼叫在for循環中:如何從Python中的單個函數委託給許多函數?

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個打印報表。但它是醜陋而乏味的。我該如何擺脫「self.list_of_objects中的東西:」並且只調用一次self.some_function(),然後讓一個裝飾器對我的列表中存在的所有東西執行for循環?

編輯:我想你可以認爲這是一個「批」模式?例如,我想在10個系統上運行「ls -l」,然後讓每個類實例處理這些命令。當他們全部完成時,下一個命令可能是在所有10個系統上「rm tmp」,依此類推。多處理也將需要,以便for循環不會在每個節點上阻塞。

+0

我不明白你的觀點。 for循環有什麼不好的地方?你想要一個班輪嗎?然後使用'map(lambda thing:thing.some_function(),self.list_of_objects)' 如果您的問題有其他更深層次的動機,例如設計原則或其他東西,請澄清一下。 –

+0

假設我有50個步驟在一個節點上進行處理,這意味着每個步驟的循環數爲50。因此,對於節點中的節點:run_cmd(「ls -l)等等。因爲我知道我想在移動到rm步驟之前在所有節點上運行此相同的命令,應該有辦法將它們批處理? –

+0

聽起來像你的問題是你有50個不同的函數,你想在列表中的所有10個元素上調用它們,你不想寫50個'for'循環,對吧? – abarnert

回答

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指出的那樣,簡單地使用maplambda是一種方式做你正在嘗試做的。我的嘗試是制定一個通用的解決方案。

你可以像這樣傳遞函數來避免傳遞一個字符串參數。

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 
+0

好的catch添加* args,** kwargs在那裏......我應該包含一個輸入與我的例子。在callFunc調用中使用它?我希望避免使用這個名字在一個字符串中的函數,但這比for循環更好... –

+0

剛剛看到你的答案的第二部分...我怎麼會在調用callFunc的函數中添加參數到some_function? –

+0

這取決於你想如何使用這些參數。每次調用'some_function'時它們是相同的,還是每個'MultipleThings'實例都是唯一的? – sberry

0

這聽起來像你的,比方說,10項list,然後你要在list運行在每個項目50個功能,而且你不想寫50 for循環。

一種可能性是寫一個包裝了一個功能:

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_functionsecond_thing.some_function實際上是不同的綁定方法;訣竅是你可以從類中獲取未綁定的方法,然後將該對象作爲顯式self參數傳遞給對象。 (嘗試打印出來first_thing.some_functionThingClass.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 s結果,你不需要。
  • 在Python 3中,map返回一個迭代器而不是list,所以它不會真正執行函數,除非您以某種方式遍歷它。 (你顯然使用2.x的今天,因爲你print聲明,但據推測有一天你會切換到3.x的)

可以解決使用itertools.imap(發電機表達或)這些問題而不是map(或列表理解)並通過例如將其饋送到0大小的deque來處置該可迭代。但在那個時候,你的代碼在做什麼並不完全清楚。

同時,明確地寫入函數意味着在發現需要時很容易修改成例如第二個版本。

+0

你的'apply'方法就是內置的'map' - 只是忽略map的返回值。 –

+0

@ThorstenKranz:你有沒有理解最後一段,或者只是懶得讀它?如果需要重寫得更清楚,請告訴我需要解決的問題。 – abarnert

+0

我編輯了它,希望更清楚地解釋爲什麼你可能不想使用'map'。 – abarnert