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 个打印语句。但它是丑陋和乏味的。我怎样才能摆脱“self.list_of_objects 中的事物:”,只需调用 self.some_function() 一次,然后也许让装饰器对我的事物列表中存在的所有事物执行 for 循环?

编辑:我猜你可以认为这是一个“批处理”模式?例如,我想在 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 指出的那样,简单地使用mapwith alambda是一种做你想做的事情的方法。我的尝试是制定一个通用的解决方案。

您可以像这样传递函数本身以避免传递字符串参数。

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

听起来您有list10 个项目,然后您想在 中的每个项目上运行 50 个函数list,并且您不想编写 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您不需要的结果。
  • 在 Python 3 中,map返回一个迭代器而不是 a list,因此它实际上根本不会执行函数,除非您以某种方式对其进行迭代。(由于您的print陈述,您今天显然在使用 2.x,但大概有一天您会切换到 3.x。)

itertools.imap您可以通过使用(或生成器表达式)而不是map(或列表推导式)并通过例如将其馈入 0-sized 来处理可迭代对象来解决这些问题deque。但到那时,您的代码在做什么并不完全清楚。

同时,显式编写函数意味着当您发现需要时很容易修改为例如第二个版本。

于 2013-01-04T08:33:15.390 回答