如何为对象列表调用相同的方法?

Dmi*_*try 62 python

假设这样的代码:

class Base:
    def start(self):
        pass
    def stop(self)
        pass

class A(Base):
    def start(self):
        ... do something for A
    def stop(self)
        .... do something for A

class B(Base):
    def start(self):

    def stop(self):

a1 = A(); a2 = A()
b1 = B(); b2 = B()

all = [a1, b1, b2, a2,.....]
Run Code Online (Sandbox Code Playgroud)

现在我想为列表中的每个对象调用方法start和stop(也许还有其他).除了写一堆像这样的函数之外,还有什么优雅的方法吗?

def start_all(all):
    for item in all:
        item.start()

def stop_all(all):
Run Code Online (Sandbox Code Playgroud)

Mar*_*sel 152

这会奏效

all = [a1, b1, b2, a2,.....]

map(lambda x: x.start(),all)    
Run Code Online (Sandbox Code Playgroud)

简单的例子

all = ["MILK","BREAD","EGGS"]
map(lambda x:x.lower(),all)
>>>['milk','bread','eggs']
Run Code Online (Sandbox Code Playgroud)

并在python3中

all = ["MILK","BREAD","EGGS"]
list(map(lambda x:x.lower(),all))
>>>['milk','bread','eggs']
Run Code Online (Sandbox Code Playgroud)

  • @dreikanter或只是`[x.start()for x in all]`? (21认同)
  • 在Python 3中,map返回一个map对象,而不是Python 2中的列表.我不确定标准过程,但我认为我应该更正它,所以我提交了一个编辑.因此,代码现在应该在Python 2和Python 3中按预期正确工作. (7认同)
  • 在Python 3中`map()`函数调用是不够的.它将创建一个生成器对象,但不会在每个列表元素上应用lambda.Lambda将在迭代map()结果时应用.`list(map(...))`将解决问题. (4认同)
  • 使用列表然后将其丢弃会给我留下非Python性的印象。因为调用的方法是带有副作用的命令性代码,所以显式的“ for”循环对于用户而言更惯用且不那么令人惊讶。如果确实需要,您可以在gen:fun(gen)中为我编写def foreach(fun,gen):。 (3认同)

小智 28

好像会有更多的Pythonic方式来做这件事,但我还没有找到它.

如果我在一堆对象上调用相同的函数(不是方法),我有时会使用"map":

map(do_something, a_list_of_objects)
Run Code Online (Sandbox Code Playgroud)

这取代了一堆看起来像这样的代码:

 do_something(a)
 do_something(b)
 do_something(c)
 ...
Run Code Online (Sandbox Code Playgroud)

但也可以用行人"for"循环来实现:

  for obj in a_list_of_objects:
       do_something(obj)
Run Code Online (Sandbox Code Playgroud)

缺点是a)你正在创建一个列表作为"map"的返回值,它只是被丢弃而b)它可能更简单,只是简单的循环变量.

你也可以使用列表理解,但这也有点滥用(再一次,创建一个丢弃列表):

  [ do_something(x) for x in a_list_of_objects ]
Run Code Online (Sandbox Code Playgroud)

对于方法,我认为其中任何一个都可以工作(具有相同的保留):

map(lambda x: x.method_call(), a_list_of_objects)
Run Code Online (Sandbox Code Playgroud)

要么

[ x.method_call() for x in a_list_of_objects ]
Run Code Online (Sandbox Code Playgroud)

所以,实际上,我认为行人(但有效)"for"循环可能是你最好的选择.

  • 我的第一反应是map(lambda x:x.member(),list).感觉就像一个非常清晰的衬里 (4认同)

Mik*_*ham 16

该方法

for item in all:
    item.start()
Run Code Online (Sandbox Code Playgroud)

简单,易读,易读,简洁.这是Python为此操作提供的主要方法.如果有帮助的话,你当然可以将它封装在一个函数中.为一般用途定义一个特殊功能可能不仅仅是写出for循环.


for*_*ran 7

也许map,但既然你不想列表,你可以写自己的......

def call_for_all(f, seq):
    for i in seq:
        f(i)
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

call_for_all(lamda x: x.start(), all)
call_for_all(lamda x: x.stop(), all)
Run Code Online (Sandbox Code Playgroud)

顺便说一下,所有都是内置功能,不要覆盖它;-)


Ant*_*sma 6

*_all() 函数非常简单,对于一些方法,我只需要编写函数。如果你有很多相同的函数,你可以写一个泛型函数:

def apply_on_all(seq, method, *args, **kwargs):
    for obj in seq:
         getattr(obj, method)(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

或者创建一个函数工厂:

def create_all_applier(method, doc=None):
    def on_all(seq, *args, **kwargs):
        for obj in seq:
            getattr(obj, method)(*args, **kwargs)
    on_all.__doc__ = doc
    return on_all

start_all = create_all_applier('start', "Start all instances")
stop_all = create_all_applier('stop', "Stop all instances")
...
Run Code Online (Sandbox Code Playgroud)

  • 这并不比直接编写 for 循环更简单。 (61认同)

not*_*peg 6

从 Python 2.6 开始,有一个operator.methodcaller函数。

所以你可以得到更优雅(更快)的东西:

from operator import methodcaller

map(methodcaller('method_name'), list_of_objects)
Run Code Online (Sandbox Code Playgroud)