Как вызвать тот же метод для списка объектов? - PullRequest
59 голосов
/ 21 апреля 2010

Предположим, что код такой:

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,.....]

Теперь я хочу вызывать методы start и stop (возможно, и другие) для каждого объекта в списке all. Есть ли какой-нибудь элегантный способ сделать это, кроме написания нескольких функций, таких как

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

def stop_all(all):

Ответы [ 7 ]

143 голосов
/ 04 февраля 2012

Это будет работать

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

map(lambda x: x.start(),all)    

простой пример

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

и в python3

all = ["MILK","BREAD","EGGS"]
list(map(lambda x:x.lower(),all))
>>>['milk','bread','eggs']
26 голосов
/ 06 июля 2011

Кажется, был бы более питонский способ сделать это, но я еще не нашел его.

Я иногда использую «map», если вызываю одну и ту же функцию (не метод) для нескольких объектов:

map(do_something, a_list_of_objects)

Это заменяет кучу кода, который выглядит следующим образом:

 do_something(a)
 do_something(b)
 do_something(c)
 ...

Но это также может быть достигнуто с помощью пешеходной петли «for»:

  for obj in a_list_of_objects:
       do_something(obj)

Недостатком является то, что а) вы создаете список как возвращаемое значение из "карты", которую только что выбросили, и б) это может быть более запутанным, чем просто вариант простого цикла.

Вы также можете использовать понимание списка, но это также немного оскорбительно (еще раз, создавая одноразовый список):

  [ do_something(x) for x in a_list_of_objects ]

Для методов, я полагаю, любой из них будет работать (с теми же оговорками):

map(lambda x: x.method_call(), a_list_of_objects)

или

[ x.method_call() for x in a_list_of_objects ]

Так что, на самом деле, я думаю, что пешеходный (но эффективный) цикл «для», вероятно, является вашей лучшей ставкой.

16 голосов
/ 21 апреля 2010

Подход

for item in all:
    item.start()

просто, легко, читабельно и кратко. Это основной подход, который Python предоставляет для этой операции. Вы, конечно, можете заключить его в функцию, если это поможет. Определение специальной функции для этого для общего использования, вероятно, будет менее понятным, чем просто запись цикла for.

7 голосов
/ 21 апреля 2010

возможно map, но так как вы не хотите создавать список, вы можете написать свой собственный ...

def call_for_all(f, seq):
    for i in seq:
        f(i)

тогда вы можете сделать:

call_for_all(lamda x: x.start(), all)
call_for_all(lamda x: x.stop(), all)

кстати, все встроенная функция, не перезаписывайте ее; -)

3 голосов
/ 21 апреля 2010

Если @Ants Aasmas ответит еще на один шаг, вы можете создать оболочку, которая принимает любой вызов метода и перенаправляет его всем элементам данного списка:

class AllOf:
    def __init__(self, elements):
        self.elements = elements
    def __getattr__(self, attr):
        def on_all(*args, **kwargs):
            for obj in self.elements:
                getattr(obj, attr)(*args, **kwargs)
        return on_all

Этот класс затем можно использовать так:

class Foo:
    def __init__(self, val="quux!"):
        self.val = val
    def foo(self):
        print "foo: " + self.val

a = [ Foo("foo"), Foo("bar"), Foo()]
AllOf(a).foo()

, который производит следующий вывод:

foo: foo
foo: bar
foo: quux!

С некоторой работой и изобретательностью, возможно, можно было бы улучшить обработку атрибутов (возвращая список значений атрибутов).

2 голосов
/ 27 июня 2018

Начиная с Python 2.6, существует функция operator.methodcaller .

Таким образом, вы можете получить что-то более элегантное (и быстрое):

from operator import methodcaller

map(methodcaller('method_name'), list_of_objects)
2 голосов
/ 21 апреля 2010

Функции * _all () настолько просты, что для нескольких методов я бы просто написал функции. Если у вас много идентичных функций, вы можете написать общую функцию:

def apply_on_all(seq, method, *args, **kwargs):
    for obj in seq:
         getattr(obj, method)(*args, **kwargs)

Или создайте фабрику функций:

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")
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...