map()
Aşırı liste kavrayışı kullanmayı tercih etmek için bir neden var mı ? Bunlardan herhangi biri genel olarak daha verimli midir yoksa genel olarak diğerinden daha fazla pitonik kabul edilir mi?
map()
Aşırı liste kavrayışı kullanmayı tercih etmek için bir neden var mı ? Bunlardan herhangi biri genel olarak daha verimli midir yoksa genel olarak diğerinden daha fazla pitonik kabul edilir mi?
Yanıtlar:
map
bazı durumlarda mikroskobik olarak daha hızlı olabilir (amaç için bir lambda yapmadığınızda, ancak aynı işlevi harita ve listcomp'da kullandığınızda). Liste kavrayışları diğer durumlarda daha hızlı olabilir ve çoğu (hepsi değil) pythonista onları daha doğrudan ve daha net olarak görür.
Tam olarak aynı işlevi kullanırken haritanın küçük hız avantajına bir örnek:
$ 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
Harita lambdaya ihtiyaç duyduğunda performans karşılaştırmasının nasıl tamamen tersine döndüğüne bir örnek:
$ 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)
okumak daha kolay [o.foo for o in objs]
?!
o
Burada olduğu gibi gereksiz isimler vermemeyi tercih ediyorum ve örnekleriniz bunun nedenini gösteriyor.
str()
örneği var.
Kılıflar
map
varsa, 'unpythonic' olarak kabul edilmesine rağmen , genellikle kullanımı makul olur . Örneğin map(sum, myLists)
, daha zarif / kısa [sum(x) for x in myLists]
. Sadece yinelemek için iki kez yazmanız gereken bir kukla değişken (örneğin sum(x) for x...
veya sum(_) for _...
veya sum(readableName) for readableName...
) oluşturmamanın zarafetini kazanırsınız . Aynı argüman modül için filter
ve reduce
herhangi bir şey için geçerlidir itertools
: zaten kullanışlı bir fonksiyonunuz varsa, devam edip bazı fonksiyonel programlama yapabilirsiniz. Bu, bazı durumlarda okunabilirlik kazanır ve diğerlerinde (örneğin acemi programcılar, çoklu argümanlar) kaybeder ... ancak kodunuzun okunabilirliği büyük ölçüde yorumlarınıza bağlıdır.map
Fonksiyonel programlama yaparken, haritaladığınız map
veya köreldiğiniz map
, veya map
fonksiyon olarak konuşmaktan başka şekilde faydalandığınız zaman, fonksiyonu saf bir soyut fonksiyon olarak kullanmak isteyebilirsiniz . Örneğin Haskell'de, adı verilen bir functor arabirimi fmap
, herhangi bir veri yapısı üzerinde eşlemeyi genelleştirir. Bu python'da çok nadirdir, çünkü python dilbilgisi sizi yineleme hakkında konuşmak için jeneratör tarzı kullanmaya zorlar; kolayca genelleme yapamazsınız. (Bu bazen iyi ve bazen kötüdür.) Muhtemelen map(f, *lists)
yapılacak makul bir şey olan nadir piton örnekleriyle karşılaşabilirsiniz . Gelebileceğim en yakın örnek sumEach = partial(map,sum)
, çok kabaca eşdeğer olan bir astar olan:def sumEach(myLists):
return [sum(_) for _ in myLists]
for
-loop kullanarak : Tabii ki sadece for-loop kullanabilirsiniz. İşlevsel programlama bakış açısından zarif olmasa da, bazen yerel olmayan değişkenler python gibi zorunlu programlama dillerinde kodu daha net hale getirir, çünkü insanlar kodu bu şekilde okumaya çok alışkındır. For-loop'lar, genellikle, sadece liste kavrama ve harita gibi bir liste oluşturmayan herhangi bir karmaşık işlemi yaparken en etkilidir (örneğin, toplama veya ağaç yapma, vb.) - en azından bellek açısından verimli (bazı nadir patolojik çöp toplama hıçkırıklarını yasaklayan en kötü sabit bir faktörden beklediğim zaman açısından değil)."Pythonism"
"Pitonik" kelimesinden hoşlanmıyorum çünkü pitoniklerin gözlerimde her zaman zarif olduğunu bulamıyorum. Bununla birlikte, map
ve filter
benzer işlevler (çok faydalı itertools
modül gibi) muhtemelen stil açısından ses kayıtsız olarak kabul edilir.
Tembellik
Verimlilik açısından, çoğu fonksiyonel programlama yapısı gibi, MAP LAZY OLABİLİR ve aslında python'da tembeldir. Bu, bunu yapabileceğiniz anlamına gelir ( python3'te ) ve bilgisayarınızın belleği tükenmez ve kaydedilmemiş tüm verilerinizi kaybetmez:
>>> map(str, range(10**100))
<map object at 0x2201d50>
Bunu bir liste kavrayışı ile yapmayı deneyin:
>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #
Liste kavrayışlarının da doğal olarak tembel olduğunu, ancak python'un tembel olmayan olarak uygulamayı seçtiğini unutmayın . Bununla birlikte, python, aşağıdaki gibi jeneratör ifadeleri biçimindeki tembel liste anlamalarını destekler:
>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>
Temel [...]
olarak sözdizimini, bir oluşturucu ifadesinde liste yapıcısına iletmek gibi düşünebilirsiniz list(x for x in range(5))
.
Kısa örnek
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))})
Liste anlamaları tembel değildir, bu nedenle daha fazla bellek gerekebilir (jeneratör anlamalarını kullanmadığınız sürece). Köşeli parantezler [...]
, özellikle parantez karmaşasında olduğunda, işleri genellikle belirginleştirir. Öte yandan, bazen yazmak gibi ayrıntılı olursunuz [x for x in...
. Yineleyici değişkenlerinizi kısa tuttuğunuz sürece, kodunuzu girintilendirmezseniz liste anlaşmaları genellikle daha açıktır. Ancak kodunuzu her zaman girintili yapabilirsiniz.
print(
{x:x**2 for x in (-y for y in range(5))}
)
veya bir şeyleri parçalayın:
rangeNeg5 = (-y for y in range(5))
print(
{x:x**2 for x in rangeNeg5}
)
Python3 için verimlilik karşılaştırması
map
şimdi tembel:
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop ^^^^^^^^^
Bu nedenle, tüm verilerinizi kullanmayacaksanız veya önceden ne kadar veriye ihtiyacınız olduğunu bilmiyorsanız, map
python3'te (ve python2 veya python3'teki jeneratör ifadeleri) son ana kadar değerlerini hesaplamaktan kaçınır. Genellikle bu genellikle herhangi bir ek yükü kullanımdan daha ağır basacaktır map
. Dezavantajı, bunun çoğu işlevsel dilin aksine python'da çok sınırlı olmasıdır: bu avantajı yalnızca verilerinize soldan sağa "sırayla" eriştiğinizde elde edersiniz, çünkü python oluşturucu ifadeleri yalnızca sipariş değerlendirilebilir x[0], x[1], x[2], ...
.
Ancak diyelim ki f
istediğimiz önceden yapılmış bir fonksiyonumuz var map
ve map
derhal değerlendirmeyi zorlayarak tembelliklerini görmezden geliyoruz list(...)
. Çok ilginç sonuçlar elde ediyoruz:
% 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>)
Sonuçlarda A / python 3.?.? İle Intel iş istasyonunda A ile gerçekleştirilen AAA / BBB / CCC biçimindedir ve B ve C python 3.2.1 ile 2013 dolaylarında AMD iş istasyonu ile gerçekleştirilmiştir son derece farklı bir donanıma sahip. Sonuç, harita ve liste kavrayışlarının, diğer rastgele faktörlerden en güçlü şekilde etkilenen performansla karşılaştırılabilir olduğu görülmektedir. Anlayabileceğimiz tek şey, garip bir şekilde, liste kavrayışlarının [...]
jeneratör ifadelerinden daha iyi performans göstermesini beklerken (...)
, jeneratör ifadelerinden de map
daha etkilidir (yine tüm değerlerin değerlendirildiğini / kullanıldığını varsayarak).
Bu testlerin çok basit bir fonksiyon (kimlik fonksiyonu) aldığını fark etmek önemlidir; ancak bu iyi bir durumdur, çünkü fonksiyon karmaşık olsaydı, performans yükü programdaki diğer faktörlere kıyasla önemsiz olacaktır. (Gibi diğer basit şeylerle test etmek hala ilginç olabilir f=lambda x:x+x
)
Python montajını okuma becerisine sahipseniz, bu dis
modülleri kullanarak perde arkasında neler olup bittiğini görebilirsiniz:
>>> 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
[...]
Sözdizimini kullanmaktan daha iyi görünüyor list(...)
. Ne yazık ki map
sınıf demontaj için biraz opak, ancak hız testimizle yapabiliriz.
map
ve filter
standart kütüphane ile birlikte itertools
doğal olarak kötü tarzı vardır. GvR aslında ya korkunç bir hata ya da sadece performans için söylemedikçe, "Pythonicness" in söylediği tek doğal sonuç, bunu aptal gibi unutmaktır ;-)
map
filter
düşmeyi / Python 3 için harika bir fikir olarak düşündü ve sadece diğer Pythonistaların isyanı onları yerleşik ad alanında tuttu ( reduce
taşındı functools
). Şahsen katılmıyorum ( map
ve filter
önceden tanımlanmış, özellikle yerleşik işlevler konusunda iyiyim, sadece lambda
gerektiğinde bunları kullanmayın ), ancak GvR temel olarak onları yıllarca Pythonic olarak adlandırmadı.
itertools
muydu? Bu cevaptan alıntı yaptığım kısım, beni rahatsız eden ana iddiadır. İdeal dünyasında olup olmadığını bilmiyorum map
ve filter
tamamen hareket edip etmeyeceğini itertools
ya functools
da tamamen gideceğini bilmiyorum , ama hangisi olursa olsun, bir kere itertools
bunun tamamen Pythonic olduğunu söylediği zaman, o zaman “Pythonic” in ne olduğunu gerçekten bilmiyorum ama "GvR'nin insanların kullanmasını önerdiklerine" benzer bir şey olabileceğini düşünmüyorum.
map
/ filter
değil itertools
. Fonksiyonel programlama mükemmel Pythonic olan ( itertools
, functools
ve operator
tüm akılda fonksiyonel programlama ile özel olarak tasarlanmış ve ben Python her zaman fonksiyonel deyimleri kullanın) ve itertools
O, özellikle oluyor bir ağrı kendinizi uygulamak olacaktır özellikler sağlar map
ve filter
jeneratör ifadeleriyle olmanın gereksiz Guido onlardan nefret ediyordu. itertools
her zaman iyiydi.
map
ve filter
kullanmalısınız.Bir objektif onlar değiliz rağmen onları tercih etmelidir nedeni "Pythonic" şudur:
Onlar argümanlar gibi işlevleri / lambdas gerektiren yeni bir kapsam tanıtmak .
Bunu bir kereden fazla ısırdım:
for x, y in somePoints:
# (several lines of code here)
squared = [x ** 2 for x in numbers]
# Oops, x was silently overwritten!
ama onun yerine şöyle demiştim:
for x, y in somePoints:
# (several lines of code here)
squared = map(lambda x: x ** 2, numbers)
o zaman her şey iyi olurdu.
Aynı değişken adını aynı kapsamda kullandığım için aptal olduğumu söyleyebilirsin.
Ben değildim. Kod başlangıçta iyiydi - ikisi x
aynı kapsamda değildi.
Sadece iç bloğu kodun farklı bir bölümüne taşıdıktan sonra sorun ortaya çıktı (okuma: bakım sırasında sorun, geliştirme değil) ve beklemiyordum.
Evet, bu hatayı asla yapmazsanız , liste kavrayışları daha zariftir.
Ama kişisel deneyimlerden (ve başkalarının da aynı hatayı yaptığını görünce), bu hatalar kodunuza girdiğinde geçmeniz gereken acıya değmeyeceğini düşünüyorum.
Kullanım map
ve filter
. Kapsamla ilgili zor teşhis edilen küçük hataları önlerler.
Durumunuza uygun olup olmadığını imap
ve ifilter
(in itertools
) kullanmayı düşünmeyi unutmayın !
map
ve / veya geçişinin mantıklı bir nedeni değildir filter
. Eğer bir şey varsa, probleminizi önlemek için en doğrudan ve mantıklı çeviri değil, JeromeJ'un işaret ettiği gibi, sızıntı yapmayan map(lambda x: x ** 2, numbers)
bir jeneratör ifadesidir list(x ** 2 for x in numbers)
. Bak Mehrdad, şahsen bu kadar kişisel oy kullanmayın, buradaki akıl yürütmenize kesinlikle katılmıyorum.
Aslında, map
liste kavrayışları Python 3 dilinde oldukça farklı davranıyor. Aşağıdaki Python 3 programına bir göz atın:
def square(x):
return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
"[1, 4, 9]" satırını iki kez yazdırmasını bekleyebilirsiniz, bunun yerine "[1, 4, 9]" ve ardından "[]" yazdırabilir. İlk bakışta squares
üç elementten oluşan bir dizi gibi görünüyor, ama ikinci kez boş olan gibi.
Python 2'de map
, liste kavrayışlarının her iki dilde yaptığı gibi düz eski bir liste döndürür. En önemli nokta map
Python 3'teki (ve imap
Python 2'deki) dönüş değerinin bir liste olmamasıdır - bu bir yineleyici!
Öğeler, bir liste üzerinde yinelemenin aksine bir yineleyici üzerinden yinelendiğinde tüketilir. Bu yüzden squares
son print(list(squares))
satırda boş görünüyor .
Özetlemek:
map
bir yineleyici değil, bir veri yapısı üretmek. Ancak tembel yineleyiciler tembel veri yapılarından daha kolaydır. Düşünce için yiyecek. Thanks @MnZrK
Liste kavrayışlarını genel olarak yapmaya çalıştığım şeyden daha etkileyici buluyorum map
- her ikisi de bunu başardı, ancak birincisi karmaşık bir lambda
ifade ne olabileceğini anlamaya çalışmanın zihinsel yükünü kurtarıyor .
Ayrıca orada Guido'nun lambda
s ve fonksiyonel işlevleri Python'a kabul etmekten en çok pişman olduğu şey olarak listelediği bir yerde bir röportaj var (bunu hazırlıksız bulamıyorum) , böylece erdem yoluyla Pythonic olmadıklarını iddia edebilirsiniz. bunun.
const
C ++ anahtar kelimesi bu satırlar boyunca büyük bir zaferdir.
lambda
o kadar topal hale getirildi (ifade yok ..), kullanımı zor ve yine de sınırlı.
İşte olası bir durum:
map(lambda op1,op2: op1*op2, list1, list2)
karşı:
[op1*op2 for op1,op2 in zip(list1,list2)]
Zip (), harita yerine liste anlayışlarını kullanmakta ısrar ederseniz şımartmanız gereken talihsiz ve gereksiz bir ek yük olduğunu tahmin ediyorum. Birisi bunu olumlu ya da olumsuz olarak açıklarsa harika olur.
zip
tembel yapabilirsinizitertools.izip
map(operator.mul, list1, list2)
. Bu çok basit sol taraftaki ifadelerde kavrayışların sakıncası olur.
Herhangi bir eşzamansız, paralel veya dağıtılmış kod yazmayı planlıyorsanız, büyük olasılıkla map
liste kavramasını tercih edersiniz - çoğu eşzamansız, paralel veya dağıtılmış paket map
pythonları aşırı yüklemek için bir işlev sağlar map
. Daha sonra uygun map
işlevi kodunuzun geri kalanına ileterek, orijinal seri kodunuzu paralel olarak (vb.) Çalıştıracak şekilde değiştirmeniz gerekmeyebilir.
Python 3, map()
bir yineleyici olduğundan, neye ihtiyacınız olduğunu aklınızda bulundurmanız gerekir: bir yineleyici veya list
nesne.
@AlexMartelli'nin daha önce de belirtildiği gibi , map()
yalnızca lambda
işlevi kullanmıyorsanız liste kavrayışından daha hızlıdır .
Size zaman karşılaştırmaları sunacağım.
Python 3.5.2 ve CPython
ben kullandım Jüpiter dizüstü ve özellikle %timeit
yerleşik sihirli komut
Ölçümler : s == 1000 ms == 1000 * 1000 us = 1000 x 1000 x 1000 ns
Kurmak:
x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
Dahili fonksiyon:
%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
fonksiyon:
%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
Jeneratör ekspresyonu diye bir şey de vardır, bkz. PEP-0289 . Bu yüzden karşılaştırmaya eklemek yararlı olacağını düşündüm
%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
Nesneye ihtiyacınız var :Özel işlevse liste kavrama özelliğini kullanın list(map())
, yerleşik işlev varsa kullanın
list
Nesneye ihtiyacınız yok , sadece tekrarlanabilir olana ihtiyacınız var:Her zaman kullanın map()
!
Bir nesnenin yöntemini çağırmak için üç yöntemi karşılaştırarak hızlı bir test çalıştırdı. Bu durumda zaman farkı ihmal edilebilir ve söz konusu fonksiyonun konusudur (@Alex Martelli'nin cevabına bakınız ). Burada, aşağıdaki yöntemlere baktım:
# 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]
Liste boyutlarını artırmak için vals
hem tamsayıların (Python int
) hem de kayan nokta numaralarının (Python float
) listelerine (değişkente saklanır) baktım . Aşağıdaki kukla sınıf DummyNum
dikkate alınır:
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
Özellikle, add
yöntem. __slots__
Özelliği, bellek boyutu azaltılması, sınıf (nitelikler) tarafından ihtiyaç duyulan toplam bellek tanımlamak için Python basit bir iyileştirmedir. Ortaya çıkan araziler.
Daha önce belirtildiği gibi, kullanılan teknik minimum bir fark yaratır ve sizin için veya belirli durumlarda en okunabilir şekilde kodlamanız gerekir. Bu durumda, liste kavrama ( map_comprehension
teknik), özellikle daha kısa listelerle, bir nesnedeki her iki ekleme türü için en hızlıdır.
Çizim ve verileri oluşturmak için kullanılan kaynak için bu macunu ziyaret edin .
map
daha önce açıklandığı gibi, sadece fonksiyon aynı şekilde çağrıldığında (yani [*map(f, vals)]
vs. [f(x) for x in vals]
) daha hızlıdır . Yani list(map(methodcaller("add"), vals))
daha hızlı [methodcaller("add")(x) for x in vals]
. map
Döngü muadili, bazı ek yükleri önleyebilecek farklı bir çağrı yöntemi kullandığında daha hızlı olmayabilir (örneğin x.add()
, methodcaller
veya lambda ifadesi ek yükünü önler ). Bu özel test için [*map(DummyNum.add, vals)]
hızlı (çünkü olacağını DummyNum.add(x)
ve x.add()
temelde aynı performansa sahip).
list()
çağrılar liste kavrayışlarından biraz daha yavaştır. Adil bir karşılaştırma için yazmanız gerekir [*map(...)]
.
list()
çağrıların genel olarak arttığını bilmiyordum . Cevapları okumak için daha fazla zaman harcamalıydım. Bu testleri adil bir karşılaştırma için tekrar çalıştıracağım, ancak farklar ihmal edilebilir.
En Pitonik yolun map
ve yerine bir liste kavrayışı kullanmak olduğunu düşünüyorum filter
. Nedeni listesi comprehensions daha net olmasıdır map
ve 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
Gördüğünüz gibi, bir anlayış ihtiyaç olarak fazladan lambda
ifade gerektirmez map
. İken Ayrıca, bir anlama da kolayca filtreleme sağlar map
gerektirir filter
olanak tanımak için.
@ Alex-martelli tarafından kodu denedim ama bazı tutarsızlıklar buldum
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
Harita çok geniş aralıklar için bile aynı süreyi alırken, liste kavrama özelliğini kullanmak benim kodumda görüldüğü gibi çok zaman alır. Bu yüzden "unpythonic" olarak değerlendirilmenin dışında, haritanın kullanımı ile ilgili herhangi bir performans sorunuyla karşılaşmadım.
map
bir liste döndüren Python 2'ye referansla yazılmıştır . Python 3'te map
tembel bir şekilde değerlendirildiğinden, basitçe çağırmak map
yeni liste öğelerinin hiçbirini hesaplamaz, bu yüzden neden bu kadar kısa süreler alırsınız.