답변:
map
경우에 따라 현미경으로 더 빠를 수 있습니다 (목적을 위해 람다를 만들지 않지만 map과 listcomp에서 동일한 기능을 사용하는 경우). 다른 경우에는 목록 이해가 더 빠를 수 있으며 대부분의 pythonista는 더 직접적이고 명확하게 생각합니다.
정확히 동일한 기능을 사용할 때 맵의 작은 속도 이점의 예 :
$ python -mtimeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop
지도에 람다가 필요할 때 성능 비교가 완전히 역전되는 예 :
$ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
map(operator.attrgetter('foo'), objs)
보다 읽기 쉽다 [o.foo for o in objs]
?!
o
여기 처럼 불필요한 이름을 소개하지 않는 것을 선호 하며, 당신의 예는 이유를 보여줍니다.
str()
예제 와 함께 요점을 가지고 있다고 생각합니다 .
사례
map
'unpythonic'으로 간주되지만 사용하는 것이 합리적 입니다. 예를 들어, map(sum, myLists)
보다 우아하고 간결합니다 [sum(x) for x in myLists]
. 반복하기 위해 두 번 입력 해야하는 더미 변수 (예 : sum(x) for x...
또는 sum(_) for _...
또는 sum(readableName) for readableName...
)를 구성하지 않아도되는 우아함을 얻습니다 . 같은 주장이filter
하고 reduce
과에서 아무것도 itertools
모듈 : 이미 함수가 편리한 경우, 당신이 가서 어떤 기능을 프로그래밍 할 수 있습니다. 이것은 어떤 상황에서는 가독성을 얻고 다른 상황에서는 읽지 못합니다 (예 : 초보 프로그래머, 여러 주장) ...하지만 코드의 가독성은 어쨌든 주석에 크게 의존합니다.map
함수 프로그래밍을 할 때, 매핑 map
또는 카레 를하는 동안 함수로서 순수한 추상 함수로 함수 를 사용하고 싶거나 함수로서 map
이야기하는 map
것으로 부터 이점을 얻을 수 있습니다. 예를 들어 Haskell에서 functor 인터페이스는 fmap
일반 데이터 구조에 대한 매핑을 일반화합니다. 파이썬 문법은 생성자 스타일을 사용하여 반복에 대해 이야기하도록 강요하기 때문에 파이썬에서는 매우 드물다. 쉽게 일반화 할 수 없습니다. (이것은 때때로 좋고 나쁘다.) 당신은 아마 map(f, *lists)
합리적인 일인 희귀 한 파이썬 예제 를 생각 해낼 수있다. 내가 올릴 수있는 가장 가까운 예 sumEach = partial(map,sum)
는 다음과 매우 비슷한 하나의 라이너입니다.def sumEach(myLists):
return [sum(_) for _ in myLists]
for
-loop 사용 : 물론 for-loop를 사용할 수도 있습니다. 함수형 프로그래밍 관점에서 볼 때 우아하지는 않지만 때로는 로컬이 아닌 변수는 파이썬과 같은 명령형 프로그래밍 언어에서 코드를 더 명확하게 만듭니다. 사람들은 그런 방식으로 코드를 읽는 데 매우 익숙하기 때문입니다. For 루프는 일반적으로 목록 이해와 같은 목록을 작성하지 않고 복잡한 작업을 수행하고 맵이 (예 : 합산 또는 트리 만들기 등) 최적화되는 경우에만 가장 효율적입니다. 기억력 측면에서 효율적입니다 (필요한 병리학 적 가비지 수집 딸꾹질을 제외하고 최악의 일정한 요인을 예상 할 수있는 시간 측면에서는 반드시 그런 것은 아닙니다)."파이썬주의"
나는 pythonic이 항상 내 눈에 우아하다는 것을 알지 못하기 때문에 "pythonic"이라는 단어를 싫어합니다. 그럼에도 불구 map
하고 filter
매우 유용 등과 유사한 기능 (itertools
모듈) 아마 스타일의 측면에서 unpythonic 간주됩니다.
게으름
대부분의 함수형 프로그래밍 구문과 같이 효율성 측면에서 MAP CAN BE LAZY 는 실제로 파이썬에서는 게으르다. 즉, python3 에서이 작업을 수행 할 수 있으며 컴퓨터에 메모리가 부족하지 않고 저장하지 않은 모든 데이터가 손실됩니다.
>>> map(str, range(10**100))
<map object at 0x2201d50>
목록 이해력으로 시도해보십시오.
>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #
리스트 이해도 본질적으로 게으르지 만, 파이썬은 그것들을 비 게으른 것으로 구현하기로 선택했습니다 . 그럼에도 불구하고, 파이썬은 다음과 같이 생성기 표현식의 형태로 게으른 목록 이해를 지원합니다.
>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>
기본적으로 [...]
구문을 생성자와 같은 목록 생성자에 전달하는 것으로 생각할 수 있습니다 list(x for x in range(5))
.
간단한 예
from operator import neg
print({x:x**2 for x in map(neg,range(5))})
print({x:x**2 for x in [-y for y in range(5)]})
print({x:x**2 for x in (-y for y in range(5))})
목록 이해는 지연되지 않으므로 더 많은 메모리가 필요할 수 있습니다 (생성자 이해를 사용하지 않는 한). 대괄호 [...]
는 특히 괄호가 엉망 일 때 특히 명확합니다. 반면에 때로는 타이핑하는 것처럼 장황하게 보일 수 [x for x in...
있습니다. 반복자 변수를 짧게 유지하는 한 일반적으로 코드를 들여 쓰지 않으면 목록 이해가 더 명확 해집니다. 그러나 항상 코드를 들여 쓸 수 있습니다.
print(
{x:x**2 for x in (-y for y in range(5))}
)
또는 헤어지다 :
rangeNeg5 = (-y for y in range(5))
print(
{x:x**2 for x in rangeNeg5}
)
Python3의 효율성 비교
map
이제 게으르다 :
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop ^^^^^^^^^
따라서 모든 데이터를 사용하지 않거나 필요한 데이터 양을 미리 알지 못하면 map
python3 (및 python2 또는 python3의 생성자 표현식)에서 필요한 마지막 순간까지 값을 계산하지 않아도됩니다. 일반적으로 이것은을 사용하는 것보다 오버 헤드보다 중요합니다 map
. 단점은 대부분의 기능적 언어와 달리 파이썬에서 매우 제한적이라는 것입니다. 파이썬 생성기 표현식은 순서 만 평가할 수 있기 때문에 왼쪽에서 오른쪽으로 "순서대로"데이터에 액세스하는 경우에만이 이점을 얻을 수 있습니다 x[0], x[1], x[2], ...
.
그러나 이제 우리는 미리 만들어진 기능이 있다고 가정 해 봅시다 f
우리가 원하는을 map
, 우리가의 게으름을 무시하고 map
즉시로 평가를 강제로 list(...)
. 우리는 매우 흥미로운 결과를 얻습니다 :
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(map(f,xs))'
10000 loops, best of 3: 165/124/135 usec per loop ^^^^^^^^^^^^^^^
for list(<map object>)
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=[f(x) for x in xs]'
10000 loops, best of 3: 181/118/123 usec per loop ^^^^^^^^^^^^^^^^^^
for list(<generator>), probably optimized
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(f(x) for x in xs)'
1000 loops, best of 3: 215/150/150 usec per loop ^^^^^^^^^^^^^^^^^^^^^^
for list(<generator>)
결과는 AAA / BBB / CCC 형식이며 여기서 A는 python 3.?.?가 포함 된 2010 년 1 월 Intel 워크 스테이션에서 수행되고 B와 C는 python 3.2.1이 포함 된 2013 년경 AMD 워크 스테이션에서 수행됩니다. 매우 다른 하드웨어로. 결과적으로지도 및 목록 이해력은 성능면에서 비슷하며 다른 임의의 요인에 의해 가장 큰 영향을받습니다. 우리는 지능형리스트 기대하면서 우리가 말할 수있는 유일한 것은, 이상한, 그 것으로 보인다 [...]
발전기 표현보다 더 잘 수행하기 위해 (...)
, map
발전기 표현 (다시 모든 값이 / 평가 사용된다고 가정) 것이 더 효율적입니다.
이러한 테스트는 매우 간단한 기능 (식별 기능)을 가정한다는 것을 인식하는 것이 중요합니다. 그러나 기능이 복잡하면 프로그램의 다른 요소와 비교하여 성능 오버 헤드가 무시할 수 있기 때문에 이것은 좋습니다. (와 같은 다른 간단한 것들로 테스트하는 것은 여전히 흥미로울 수 있습니다 f=lambda x:x+x
)
파이썬 어셈블리를 읽는 데 능숙하다면, dis
모듈을 사용하여 실제로 그 장면이 어떻게 진행되고 있는지 확인할 수 있습니다.
>>> listComp = compile('[f(x) for x in xs]', 'listComp', 'eval')
>>> dis.dis(listComp)
1 0 LOAD_CONST 0 (<code object <listcomp> at 0x2511a48, file "listComp", line 1>)
3 MAKE_FUNCTION 0
6 LOAD_NAME 0 (xs)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE
>>> listComp.co_consts
(<code object <listcomp> at 0x2511a48, file "listComp", line 1>,)
>>> dis.dis(listComp.co_consts[0])
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 18 (to 27)
9 STORE_FAST 1 (x)
12 LOAD_GLOBAL 0 (f)
15 LOAD_FAST 1 (x)
18 CALL_FUNCTION 1
21 LIST_APPEND 2
24 JUMP_ABSOLUTE 6
>> 27 RETURN_VALUE
>>> listComp2 = compile('list(f(x) for x in xs)', 'listComp2', 'eval')
>>> dis.dis(listComp2)
1 0 LOAD_NAME 0 (list)
3 LOAD_CONST 0 (<code object <genexpr> at 0x255bc68, file "listComp2", line 1>)
6 MAKE_FUNCTION 0
9 LOAD_NAME 1 (xs)
12 GET_ITER
13 CALL_FUNCTION 1
16 CALL_FUNCTION 1
19 RETURN_VALUE
>>> listComp2.co_consts
(<code object <genexpr> at 0x255bc68, file "listComp2", line 1>,)
>>> dis.dis(listComp2.co_consts[0])
1 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (x)
9 LOAD_GLOBAL 0 (f)
12 LOAD_FAST 1 (x)
15 CALL_FUNCTION 1
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> evalledMap = compile('list(map(f,xs))', 'evalledMap', 'eval')
>>> dis.dis(evalledMap)
1 0 LOAD_NAME 0 (list)
3 LOAD_NAME 1 (map)
6 LOAD_NAME 2 (f)
9 LOAD_NAME 3 (xs)
12 CALL_FUNCTION 2
15 CALL_FUNCTION 1
18 RETURN_VALUE
[...]
보다 구문 을 사용하는 것이 좋습니다 list(...)
. 슬프게도 map
클래스는 분해하기에 약간 불투명하지만 속도 테스트로 인해 만들 수 있습니다.
map
과 filter
표준 라이브러리와 함께 itertools
본질적으로 나쁜 스타일입니다. GVR는 실제로 어느 끔찍한 실수했다거나 전적으로 성능을 위해,이 경우 당연한 결론은 ;-) 것 "Pythonicness가"라고하는 것은 바보 같은 잊어하는 것입니다 말한다 않는 한
map
filter
Droping / 이 Python 3에 대한 좋은 아이디어 라고 생각 했으며 다른 Pythonista의 반란만으로도 내장 네임 스페이스에 유지했습니다 ( reduce
로 이동하는 동안 functools
). 나는 개인적으로 동의 ( map
및 filter
미세 사전 정의로, 특히 내장 함수, A는 경우 단지 그들을 사용하지 않을 lambda
필요하다)하지만, GVR은 기본적 년 동안하지 파이썬을 촉구했다.
itertools
이었습니까? 이 답변에서 인용 한 부분은 나를 괴롭히는 주요 주장입니다. 나는 그의 이상적인 세계에서 여부, 모르는 map
및 filter
이동 것 itertools
(또는 functools
) 또는 완전히 이동하지만, 둘 중 하나가 말한다 일단의 경우 itertools
전체를 unPythonic이다, 나는 정말 "파이썬"이 뭔지 모르 그 의미는 "GvR이 사람들이 사용하도록 권장하는 것과"비슷할 수는 없다고 생각합니다.
map
/ 만 주소 지정 filter
하지 않았습니다 itertools
. 함수 프로그래밍 완벽하게 파이썬이다 ( itertools
, functools
그리고 operator
모든 염두에 함수형 프로그래밍으로 특별히 설계되었으며, 파이썬의 모든 시간의 기능 숙어를 사용), 그리고 itertools
그것은, 특히있어 고통이 자신을 구현하는 것입니다 기능을 제공 map
하고 filter
발전기식이되고 중복 귀도는 그들을 미워하게 만들었습니다. itertools
항상 괜찮 았습니다.
map
그리고 filter
이해력을 사용해야합니다 .목적 당신은 그들이하지 않은 경우에도 그들을 좋아해야하는 이유 이유는 "파이썬은"이것이다 :
그들은 인수 등의 기능 / 람다 요구하는 새로운 범위를 소개를 .
나는 이것에 두 번 이상 물렸다.
for x, y in somePoints:
# (several lines of code here)
squared = [x ** 2 for x in numbers]
# Oops, x was silently overwritten!
그러나 대신에 나는 말했다 :
for x, y in somePoints:
# (several lines of code here)
squared = map(lambda x: x ** 2, numbers)
그러면 모든 것이 잘되었을 것입니다.
같은 범위에서 동일한 변수 이름을 사용하는 것에 대해 바보라고 말할 수 있습니다.
나는 아니었다. 코드는 원래 괜찮 았습니다. 두 코드는 x
같은 범위에 없었습니다. 내부 블록을 코드의 다른 섹션으로 옮긴
후에야 문제가 발생했습니다 (읽기 : 유지 관리 중 문제, 개발 아님).
예, 이 실수 를 하지 않으면 목록 이해력이 더 우아합니다.
그러나 개인적인 경험 (그리고 다른 사람들이 같은 실수를하는 것을 보았을 때)에서 나는이 버그가 코드에 들어갔을 때 겪어야 할 고통이 가치가 없다고 생각합니다.
map
및을 사용하십시오 filter
. 미묘한 진단하기 어려운 범위 관련 버그를 방지합니다.
사용을 고려하는 것을 잊지 마십시오 imap
과 ifilter
(에 itertools
그들은 상황에 맞는 적절한 경우)!
map
그리고 / 또는로 전환하는 논리적 인 이유는 아닙니다 filter
. 무엇보다도, 문제를 피하기위한 가장 직접적이고 논리적 인 번역 은 JeromeJ가 이미 지적했듯이 누출되지 않는 map(lambda x: x ** 2, numbers)
생성기 표현 list(x ** 2 for x in numbers)
에 대한 것이 아닙니다. Mehrdad를보고, 개인적으로 공감하지 마십시오. 나는 당신의 추론에 강력히 동의하지 않습니다.
실제로, map
리스트 이해는 파이썬 3 언어에서 상당히 다르게 행동합니다. 다음 Python 3 프로그램을 살펴보십시오.
def square(x):
return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
"[1, 4, 9]"줄을 두 번 인쇄해야하지만 대신 "[1, 4, 9]"뒤에 "[]"가 인쇄됩니다. 처음 보았을 때 squares
세 가지 요소의 시퀀스로 작동하지만 두 번째는 빈 요소로 동작합니다.
파이썬 2에서 언어 map
는 목록 이해가 두 언어에서와 같이 평범한 오래된 목록을 반환합니다. 요점은 map
Python 3 (및 imap
Python 2) 의 반환 값이 목록이 아니라 반복 자라는 것입니다!
목록을 반복 할 때와 달리 반복자를 반복 할 때 요소가 소비됩니다. 이것이 squares
마지막 print(list(squares))
줄 에서 비어있는 이유 입니다.
요약:
map
반복자가 아닌 데이터 구조를 생성하는 것입니다. 그러나 게으른 반복자는 게으른 데이터 구조보다 쉽습니다. 생각할 거리. 감사합니다 @MnZrK
나는 목록 이해가 일반적으로 내가하려는 일보다 더 표현력이 뛰어나다는 것을 알았 map
습니다. 둘 다 완료하지만 전자는 복잡한 것이 무엇인지 이해하려고 노력하는 정신적 부담을 덜어줍니다.lambda
표현이 .
Guido lambda
가 파이썬으로 받아들이는 것에 대해 가장 후회하는 것으로 s와 기능적 기능을 나열하는 곳에서 (내가 손으로 찾을 수없는) 인터뷰가 있습니다 . 그래서 그들은 미덕에 의해 비 파이썬 적이라는 주장을 할 수 있습니다 그것의.
const
C ++ 의 키워드는 이러한 라인에서 큰 승리입니다.
lambda
사용하기 어려우며 제한하기에 너무 불명예 스럽습니다.
가능한 사례는 다음과 같습니다.
map(lambda op1,op2: op1*op2, list1, list2)
대:
[op1*op2 for op1,op2 in zip(list1,list2)]
zip ()은 불행히도 불필요한 오버 헤드라고 생각합니다.지도 대신 목록 이해를 고집하는 경우 탐닉해야합니다. 누군가 긍정적 으로든 부정적 으로든 이것을 명확히하면 좋을 것입니다.
zip
을 사용하여 게으를 수 있습니다.itertools.izip
map(operator.mul, list1, list2)
. 이해가 어색 해지는 것은 바로이 매우 간단한 왼쪽 표현입니다.
비동기식, 병렬 식 또는 분산 형 코드를 작성하려는 경우 map
대부분의 비동기식, 병렬 식 또는 분산 형 패키지가 map
python에 과부하를 가하는 기능을 제공하므로 목록 이해를 선호 할 것입니다 map
. 그런 다음 map
나머지 코드에 적절한 기능을 전달하면 원래 직렬 코드를 수정하여 병렬로 실행하지 않아도 될 수 있습니다.
따라서 Python 3 map()
은 반복자이므로 필요한 것이 무엇인지 명심해야합니다. 반복자 또는list
객체와 합니다.
@AlexMartelli 이미으로 언급 , map()
당신이 사용하지 않는 경우에만 빠른 지능형리스트보다lambda
기능을.
시간 비교를하겠습니다.
파이썬 3.5.2 및 CPython과
내가 사용했던 목성 노트북을 , 특히 %timeit
내장 마법 명령
측정 : S == 1000 MS == 1000 * 1000 μS가 = 1000 * 1000 * 1000 ns의
설정:
x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
내장 기능 :
%timeit map(sum, x_list) # creating iterator object
# Output: The slowest run took 9.91 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 277 ns per loop
%timeit list(map(sum, x_list)) # creating list with map
# Output: 1000 loops, best of 3: 214 µs per loop
%timeit [sum(x) for x in x_list] # creating list with list comprehension
# Output: 1000 loops, best of 3: 290 µs per loop
lambda
함수:
%timeit map(lambda i: i+1, i_list)
# Output: The slowest run took 8.64 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 325 ns per loop
%timeit list(map(lambda i: i+1, i_list))
# Output: 1000 loops, best of 3: 183 µs per loop
%timeit [i+1 for i in i_list]
# Output: 10000 loops, best of 3: 84.2 µs per loop
생성기 표현식과 같은 것도 있습니다 ( PEP-0289 참조) . 그래서 비교에 추가하는 것이 도움이 될 것이라고 생각했습니다.
%timeit (sum(i) for i in x_list)
# Output: The slowest run took 6.66 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 495 ns per loop
%timeit list((sum(x) for x in x_list))
# Output: 1000 loops, best of 3: 319 µs per loop
%timeit (i+1 for i in i_list)
# Output: The slowest run took 6.83 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 506 ns per loop
%timeit list((i+1 for i in i_list))
# Output: 10000 loops, best of 3: 125 µs per loop
list
객체 가 필요 합니다 :사용자 정의 함수 인 경우 목록 이해를 사용 list(map())
하고 기본 제공 함수가있는 경우 사용
list
객체 가 필요하지 않고 반복 가능한 객체 만 필요합니다.항상 사용하십시오 map()
!
객체의 메소드를 호출하기 위해 세 가지 메소드를 비교하는 빠른 테스트를 실행했습니다. 이 경우 시차는 무시할 만하고 문제의 기능의 문제입니다 (@Alex Martelli의 응답 참조 ). 여기에서는 다음 방법을 살펴 보았습니다.
# map_lambda
list(map(lambda x: x.add(), vals))
# map_operator
from operator import methodcaller
list(map(methodcaller("add"), vals))
# map_comprehension
[x.add() for x in vals]
목록 크기를 늘리기 위해 vals
정수 (Python int
) 및 부동 소수점 숫자 (Python float
)의 목록 (변수에 저장 됨)을 살펴 보았습니다 . 다음과 같은 더미 클래스 DummyNum
가 고려됩니다.
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
구체적으로, add
방법. 이 __slots__
속성은 클래스에서 필요한 총 메모리 (속성)를 정의하여 메모리 크기를 줄이는 Python의 간단한 최적화입니다. 결과 플롯은 다음과 같습니다.
앞에서 언급 한 바와 같이, 사용 된 기술은 최소한의 차이를 만들어 내기 때문에 가장 읽기 쉬운 방식으로 또는 특정 상황에서 코딩해야합니다. 이 경우 목록 이해 (map_comprehension
기술)는 객체의 두 가지 유형의 추가, 특히 짧은 목록에서 가장 빠릅니다.
플롯과 데이터를 생성하는 데 사용되는 소스를 보려면 이 페이스트 빈 을 방문하십시오 .
map
함수가 정확히 같은 방식으로 호출되는 경우 (예 : [*map(f, vals)]
vs. [f(x) for x in vals]
) 더 빠릅니다 . 그래서 list(map(methodcaller("add"), vals))
보다 더 빨리이다 [methodcaller("add")(x) for x in vals]
. map
루핑 대응 일부 오버 헤드를 피할 수있는 다른 호출 방법을 사용하는 경우 빠르게하지 않을 수 (예를 x.add()
피할 methodcaller
또는 람다 식 오버). 이 특정 테스트 케이스의 경우, [*map(DummyNum.add, vals)]
빠른 (때문에 것 DummyNum.add(x)
와 x.add()
기본적으로 동일한 성능을 가지고).
list()
호출은 목록 이해보다 약간 느립니다. 공정한 비교를 위해서는 글을 써야 [*map(...)]
합니다.
list()
호출이 오버 헤드를 증가 시킨다는 것을 알지 못했습니다 . 답변을 읽는 데 더 많은 시간을 보냈습니다. 공정한 비교를 위해 이러한 테스트를 다시 실행하지만 차이점은 무시할 수 있습니다.
가장 파이썬적인 방법은 map
and 대신 목록 이해를 사용하는 것입니다 filter
. 그 이유는 목록 이해력이 map
and 보다 명확하기 때문 filter
입니다.
In [1]: odd_cubes = [x ** 3 for x in range(10) if x % 2 == 1] # using a list comprehension
In [2]: odd_cubes_alt = list(map(lambda x: x ** 3, filter(lambda x: x % 2 == 1, range(10)))) # using map and filter
In [3]: odd_cubes == odd_cubes_alt
Out[3]: True
아시다시피, 이해력은 필요에 따라 추가 lambda
표현이 map
필요 하지 않습니다 . 또한, 이해도 필터링을 쉽게 할 수 있지만 필터링을 허용 map
해야 filter
합니다.
@ alex-martelli의 코드를 시도했지만 약간의 불일치를 발견했습니다.
python -mtimeit -s "xs=range(123456)" "map(hex, xs)"
1000000 loops, best of 5: 218 nsec per loop
python -mtimeit -s "xs=range(123456)" "[hex(x) for x in xs]"
10 loops, best of 5: 19.4 msec per loop
지도는 매우 넓은 범위에서도 동일한 시간이 걸리며 목록 이해를 사용하면 코드에서 알 수 있듯이 많은 시간이 걸립니다. 따라서 "비 pythonic"으로 간주되는 것 외에도지도 사용과 관련된 성능 문제에 직면하지 않았습니다.
map
은 목록을 반환하는 Python 2와 관련하여 작성되었을 가능성이 큽니다 . 파이썬 3에서는 map
게으르게 평가되므로 단순히 호출 map
하면 새로운 목록 요소가 계산되지 않으므로 짧은 시간을 얻는 이유는 무엇입니까?