我需要在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个打印语句。但这是丑陋乏味的。我怎样才能摆脱“for self.list_of_objects:”中的东西,只需调用self.some_function()一次,然后让装饰者对我的事物列表中存在的所有东西进行for循环?
编辑:我想你可以认为这是一种“批量”模式吗?例如,我想在10个系统上运行“ls -l”,然后让每个类实例处理这些命令。完成所有操作后,下一个命令可能是所有10个系统上的“rm tmp”,依此类推。还需要多处理,以便for循环不会在每个节点上阻塞。
答案 0 :(得分: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
与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
答案 1 :(得分:0)
听起来你有一个list
,比方说10项,然后你想在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_function
和second_thing.some_function
实际上是不同的绑定方法;诀窍是你可以从类中获取未绑定的方法,然后将对象作为显式self
参数传递给它。 (尝试打印出first_thing.some_function
,ThingClass.some_function
,type(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
或理解是有问题的。list
个结果。map
返回一个迭代器而不是list
,因此它根本不会实际执行这些函数,除非你以某种方式迭代它。 (你今天显然使用的是2.x,因为你的print
语句,但大概有一天你会切换到3.x.)您可以使用itertools.imap
(或生成器表达式)代替map
(或列表推导)来解决这些问题,并通过例如将其提供给0大小来处理迭代deque
。但在那时,你的代码正在做什么并不完全清楚。
同时,明确地编写函数意味着当您发现需要时,很容易将其修改为例如第二个版本。