개체 목록에 대해 동일한 메서드를 호출하는 방법은 무엇입니까?


79

다음과 같은 코드를 가정하십시오.

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 메서드를 호출하고 싶습니다. 다음과 같은 많은 함수를 작성하는 것 외에는 우아한 방법이 있습니까?

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

def stop_all(all):

1
여러 기능이 두 기능입니까?
SilentGhost 2010

4
이것은 귀하의 질문과 관련이 없지만 귀하의 예제에는 왜 기본 클래스가 필요한지 분명한 이유가 없습니다. 파이썬은 관련없는 객체의 목록을 갖게되어 매우 기뻐할 것이며, 모두 'start'및 'stop'메소드를 가지고있는 한 메소드를 호출하는 동안 계속 반복 할 수 있습니다.
Duncan

1
귀하의 정의 Base쓸모없는 방법으로 다음의 행동을 정의 A하고 B파이썬에서 가난한 디자인을 반영한다. 오히려 추상 기본 클래스를 사용하는 것보다, 당신은 정의 할 수 AB그들이 인터페이스를 공유하는 상호 교환하는 한 그들을 사용합니다. 당신의 현재 방식은 쓸모없는 수업을 만들어 내는데, 이것은 당신이 필요로하지 않는 여분의 것입니다.
Mike Graham

답변:


7

* _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")
...

56
이것은 for 루프를 직접 작성하는 것보다 더 간단하지 않습니다.
Mike Graham

178

이것은 작동합니다

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']

10
Python 3에서 map은 Python 2와 같은 목록이 아닌 map 객체를 반환합니다. 표준 절차는 확실하지 않지만 수정해야한다고 생각하여 편집을 제출했습니다. 따라서 코드는 이제 예상대로 Python 2와 Python 3에서 올바르게 작동합니다.
leetNightshade

1
또한 이것은 더 Pythonic 대답처럼 느껴지며 받아 들여 져야합니다. 지도는 좋은 선택입니다. 저는 지금까지 람다를 사용한 적이 없어서 감사합니다.
leetNightshade 2013 년

6
Python 3에서는 map()함수 호출만으로는 충분하지 않습니다. 생성기 객체를 생성하지만 각 목록 요소에 람다를 적용하지 않습니다. Lambda는 map () 결과를 반복 할 때 적용됩니다. list(map(...))문제를 해결할 것입니다.
Alex Musayev 2013-08-07

24
@dreikanter 아니면 그냥 [x.start() for x in all]?
endolith 2014

6
목록을 사용하고 그것을 버리는 것은 나를 비파이 토닉으로 공격합니다. 호출 된 메서드는 부작용이있는 명령형 코드이므로 명시 적 for루프는 독자에게 더 관용적이고 덜 놀랍습니다. 정말로해야한다면 def foreach(fun, gen): for i in gen: fun(gen).
Thomas

32

좀 더 파이썬적인 방법이있을 것 같지만 아직 찾지 못했습니다.

여러 객체에 대해 동일한 함수 (메서드가 아님)를 호출하는 경우 가끔 "맵"을 사용합니다.

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) 그냥 버려지는 "맵"에서 반환 값으로 목록을 만들고 b) 단순한 루프 변형보다 더 혼란 스러울 수 있다는 것입니다.

목록 이해력을 사용할 수도 있지만 약간 모욕적입니다 (다시 한 번 던져 버리는 목록 생성).

  [ 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 ]

따라서 실제로는 보행자 (아직 효과적인) "for"루프가 아마도 최선의 방법이라고 생각합니다.


4
첫 번째 반응은 map (lambda x : x.member (), list)였습니다. 그것은 꽤 명확한 하나의 라이너처럼 느껴졌습니다
Mark Essel

"보행자"for 루프에 대한 좋은 결론입니다. 이 CL을한다면, 당신은 것입니다 mapcarmapc은 "목록을 던져 / 목록을 원하는"경우를 구별 할 수 있습니다. 그러나 슬프 도다 ...
주앙 Tavora

21

접근

for item in all:
    item.start()

간단하고, 쉽고, 읽기 쉽고, 간결합니다. 이것이 파이썬이이 작업을 위해 제공하는 주요 접근 방식입니다. 도움이된다면 함수에 확실히 캡슐화 할 수 있습니다. 일반적인 용도로이를위한 특수 함수를 정의하는 것은 for 루프를 작성하는 것보다 덜 명확합니다.


7

어쩌면 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

Python 2.6부터 연산자가 있습니다. 함수가 있습니다.

따라서 더 우아하고 빠른 것을 얻을 수 있습니다.

from operator import methodcaller

map(methodcaller('method_name'), list_of_objects)

1
python3에 대한 최선의 접근 방식은 무엇입니까?
Neil

python3에서이 작품 @Neil, 유일하게 다른이 즉 map반환 3의 반복자가 아닌 목록
notbad.jpeg

3

@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 : 바
foo : quux!

약간의 작업과 독창성을 통해 속성도 처리하도록 향상 될 수 있습니다 (속성 값 목록 반환).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.