부작용에 대한 목록 이해력을 사용하는 것이 Pythonic입니까?


108

반환 값이 아닌 부작용을 위해 호출하는 함수 (화면에 인쇄, GUI 업데이트, 파일로 인쇄 등)를 생각해보십시오.

def fun_with_side_effects(x):
    ...side effects...
    return y

이제이 func를 호출하기 위해 목록 이해력을 사용하는 것이 Pythonic입니까 ?

[fun_with_side_effects(x) for x in y if (...conditions...)]

목록을 어디에도 저장하지 않습니다.

또는이 func를 다음과 같이 호출해야합니다.

for x in y:
    if (...conditions...):
        fun_with_side_effects(x)

어느 것이 더 낫고 그 이유는 무엇입니까?


6
이것은 경계선이지만 아마도 지원보다는 반대를받을 것입니다. ^) : 나는 밖으로이 하나 앉아 갈거야
jcomeau_ictx

6
이것은 쉬운 선택입니다. 가독성이 중요합니다-두 번째 방법으로 수행하십시오. 당신이 당신의 화면이 별도의 라인에 맞지 않을 경우 더 큰 모니터 :) 얻을
존 라 Rooy

1
목록 이해력은 "명시적인 것이 암시적인 것보다 낫다"를 위반하기 때문에 비 파이썬 적입니다. 다른 구조에서 루프를 숨기고 있습니다.
Fred Foo 2011

3
@larsmans : GvR이 처음에 목록 이해를 도입했을 때만 깨달았다면!
Steve Jessop 2011

2
@larsmans, Steve Jessop, 목록 이해를 루프로 생각하는 것은 잘못된 것 같습니다. 루프로 구현할 수도 있지만 이와 같은 구성의 요점은 집계 데이터를 기능적이고 (개념적으로) 병렬 방식으로 작동하는 것입니다. 구문에 문제가있는 for ... in경우 두 경우 모두 사용되어 이와 같은 질문으로 이어집니다!
senderle 2011-04-23

답변:


84

그렇게하는 것은 매우 반 파이 토닉이며 노련한 Pythonista는 당신에게 지옥을 줄 것입니다. 중간 목록은 생성 된 후 버려 지므로 잠재적으로 매우 크고 생성 비용이 많이들 수 있습니다.


5
그렇다면 더 비단뱀적인 방법은 무엇일까요?
Joachim Sauer 2011

6
목록을 유지하지 않는 사람; 즉, 두 번째 방법의 일부 변형 (나는 for이전에 제넥스를 사용하여 를 제거 하는 것으로 알려져 있습니다 if).
Ignacio Vazquez-Abrams 2011

6
@Joachim Sauer : 위의 예 2. 적절하고 명시 적이며 목록을 이해하지 못하는 루프. 명백한. 명확한. 분명한.
S.Lott 2011

31

사람들이 말했듯이 필요하지 않은 큰 임시 목록을 만들 것이기 ​​때문에 목록 이해력을 사용해서는 안됩니다 . 다음 두 가지 방법은 동일합니다.

consume(side_effects(x) for x in xs)

for x in xs:
    side_effects(x)

man 페이지 consume에서 정의 itertools:

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

물론 후자는 더 명확하고 이해하기 쉽습니다.


@ 폴 : 그래야한다고 생각합니다. 그리고 실제로 map함수형 프로그래밍을 해본 적이 없다면 직관적이지 않을 수도 있습니다.
Katriel 2011-04-22

4
이것이 특히 관용적 인 것인지 확실하지 않습니다. 명시 적 루프를 사용하는 것보다 이점이 없습니다.
Marcin

1
해결책은consume = collections.deque(maxlen=0).extend
PaulMcG 2010 년

24

목록 이해는 목록을 만드는 데 사용됩니다. 그리고 실제로 목록을 작성하지 않는 한 목록 이해를 사용 해서는 안됩니다 .

그래서 두 번째 옵션을 얻었습니다. 목록을 반복 한 다음 조건이 적용될 때 함수를 호출합니다.


6
나는 더 나아가서 목록 이해력 내부의 부작용이 비정상적이고 예상치 못한 것이므로 악의적이라고 말할 것입니다.
Mark Ransom

11

두 번째가 더 좋습니다.

코드를 이해해야하는 사람을 생각해보십시오. 첫 번째로 쉽게 업장을 얻을 수 있습니다 :)

filter ()를 사용하여 둘 사이의 중간에 갈 수 있습니다. 예를 고려하십시오.

y=[1,2,3,4,5,6]
def func(x):
    print "call with %r"%x

for x in filter(lambda x: x>3, y):
    func(x)

10
귀하의 람다는 lambda x : x > 3.
PaulMcG 2011

필터도 필요 없습니다. 여기에 생성기 표현식을 괄호 안에 넣으십시오 for el in (x for x in y if x > 3):. elx같은 이름을 가질 수 있지만, 그 사람을 혼동 수 있습니다.
Omnifarious

3

목표에 따라 다릅니다.

목록의 각 개체에 대해 몇 가지 작업을 수행하려는 경우 두 번째 방법을 채택해야합니다.

다른 목록에서 목록을 생성하려는 경우 목록 이해를 사용할 수 있습니다.

명시적인 것이 암시적인 것보다 낫습니다. 단순한 것이 복잡한 것보다 낫습니다. (파이썬 젠)


0

넌 할 수있어

for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass

하지만 그다지 예쁘지 않습니다.


-1

부작용에 대한 목록 이해력을 사용하는 것은 추악하고 비파이 토닉이며 비효율적이며 저는 그렇게하지 않을 것입니다. for루프 for는 부작용이 중요한 절차 적 스타일을 나타 내기 때문에 대신 루프를 사용합니다 .

그러나 부작용에 대한 목록 이해를 절대적으로 사용해야한다면 생성기 표현식을 대신 사용하여 비 효율성을 피해야합니다. 이 스타일을 절대적으로 고집한다면 다음 두 가지 중 하나를 수행하십시오.

any(fun_with_side_effects(x) and False for x in y if (...conditions...))

또는:

all(fun_with_side_effects(x) or True for x in y if (...conditions...))

이들은 생성기 표현식이며 버려지는 무작위 목록을 생성하지 않습니다. 나는 생각 all나는 그들 모두가 혼란하고 사용할 수 없습니다한다고 생각하지만 형태가 약간 아마 더 분명하다.

나는 이것이 추악하다고 생각하고 실제로 코드에서 그것을하지 않을 것입니다. 하지만 이런 방식으로 루프를 구현해야한다고 주장한다면 그렇게 할 것입니다.

나는 목록 이해력과 그들의 ilk가 적어도 기능적 스타일과 약간 닮은 것을 사용하려는 시도를 나타내야한다고 생각하는 경향이 있습니다. 그 가정을 깨뜨리는 부작용이있는 것을 넣으면 사람들이 당신의 코드를 더주의 깊게 읽어야하는데, 그것은 나쁜 것이라고 생각합니다.


fun_with_side_effectsTrue를 반환 하면 어떻게 됩니까?
카트리 엘

7
나는이 치료법이 질병보다 더 나쁘다고 생각합니다-itertools.consume은 훨씬 더 깨끗합니다.
PaulMcG 2011

@PaulMcG- itertools.consume부작용이있는 이해력을 사용하는 것이 추악하기 때문에 더 이상 존재하지 않습니다.
Omnifarious

1
내가 착각 한 것으로 밝혀졌고 stdlib의 메소드로 존재 하지 않았습니다 . 그것은 이다 itertools 워드 프로세서의 조리법 : docs.python.org/3/library/...
PaulMcG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.