Как вызвать тот же метод для списка объектов?
Предположим, что такой код:
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):
Ответы
Ответ 1
Функции * _all() настолько просты, что для нескольких методов я просто написал функции. Если у вас много одинаковых функций, вы можете написать общую функцию:
def apply_on_all(seq, method, *args, **kwargs):
for obj in seq:
getattr(obj, method)(*args, **kwargs)
Или создайте функцию factory:
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")
...
Ответ 2
Это будет работать
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']
Ответ 3
Похоже, что это будет более питонический способ сделать это, но я еще не нашел его.
Я иногда использую "карту", если я вызываю одну и ту же функцию (а не метод) на кучу объектов:
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)
Недостатком является то, что a) вы создаете список как возвращаемое значение из "карты", которое просто выбрасывается, и б) он может быть более запутанным, чем просто простой вариант цикла.
Вы также можете использовать понимание списка, но это также немного оскорбительно (еще раз, создав список отбрасывания):
[ 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 ]
Итак, на самом деле, я думаю, что пешеходный (но эффективный) цикл "для", вероятно, лучший выбор.
Ответ 4
Подход
for item in all:
item.start()
прост, понятен и понятен. Это основной подход, который Python обеспечивает для этой операции. Вы можете, конечно, инкапсулировать его в функцию, если это что-то помогает. Определение специальной функции для этого для общего использования, вероятно, будет менее понятно, чем просто написать цикл for.
Ответ 5
возможно 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)
Кстати, все это встроенная функция, не перезаписывайте ее, -)
Ответ 6
Взяв @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!
С некоторой работой и изобретательностью она, вероятно, может быть улучшена для обработки атрибутов (возврат списка значений атрибутов).