Apakah ada alasan untuk memilih menggunakan map()
pemahaman daftar berlebihan atau sebaliknya? Apakah salah satu dari mereka umumnya lebih efisien atau secara umum dianggap lebih pythonic daripada yang lain?
Apakah ada alasan untuk memilih menggunakan map()
pemahaman daftar berlebihan atau sebaliknya? Apakah salah satu dari mereka umumnya lebih efisien atau secara umum dianggap lebih pythonic daripada yang lain?
Jawaban:
map
dalam beberapa kasus mungkin lebih cepat secara mikroskopis (ketika Anda TIDAK membuat lambda untuk tujuan itu, tetapi menggunakan fungsi yang sama di peta dan listcomp). Pemahaman daftar mungkin lebih cepat dalam kasus lain dan kebanyakan (tidak semua) pythonista menganggapnya lebih langsung dan lebih jelas.
Contoh keunggulan kecepatan kecil peta saat menggunakan fungsi yang persis sama:
$ 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
Contoh bagaimana perbandingan kinerja terbalik sepenuhnya ketika peta membutuhkan lambda:
$ 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)
lebih mudah dibaca daripada [o.foo for o in objs]
?!
o
sini, dan contoh Anda menunjukkan alasannya.
str()
contohnya.
Kasing
map
, meskipun itu dianggap 'unpythonic'. Misalnya, map(sum, myLists)
lebih elegan / singkat daripada [sum(x) for x in myLists]
. Anda mendapatkan keanggunan karena tidak harus membuat variabel dummy (mis sum(x) for x...
atau sum(_) for _...
atau sum(readableName) for readableName...
) yang harus Anda ketik dua kali, hanya untuk beralih. Argumen yang sama berlaku untuk filter
dan reduce
dan apa pun dari itertools
modul: jika Anda sudah memiliki fungsi berguna, Anda bisa melanjutkan dan melakukan pemrograman fungsional. Ini mendapatkan keterbacaan dalam beberapa situasi, dan kehilangan pembacaannya di situasi lain (mis. Programmer pemula, banyak argumen) ... tetapi keterbacaan kode Anda sangat tergantung pada komentar Anda.map
fungsi sebagai fungsi abstrak murni saat melakukan pemrograman fungsional, di mana Anda memetakan map
, atau menjelajah map
, atau mendapat manfaat dari berbicara tentang map
fungsi. Dalam Haskell misalnya, antarmuka functor disebut fmap
menggeneralisasi pemetaan atas struktur data apa pun. Ini sangat tidak biasa dalam python karena tata bahasa python memaksa Anda untuk menggunakan generator-style untuk berbicara tentang iterasi; Anda tidak dapat menggeneralisasikannya dengan mudah. (Ini terkadang baik dan kadang-kadang buruk.) Anda mungkin dapat menemukan contoh python langka di mana map(f, *lists)
hal yang masuk akal untuk dilakukan. Contoh terdekat yang bisa saya temukan adalah sumEach = partial(map,sum)
, yang merupakan satu-liner yang kira-kira setara dengan:def sumEach(myLists):
return [sum(_) for _ in myLists]
for
-loop : Tentu saja Anda juga bisa menggunakan for-loop. Meskipun tidak elegan dari sudut pandang fungsional-pemrograman, kadang-kadang variabel non-lokal membuat kode lebih jelas dalam bahasa pemrograman imperatif seperti python, karena orang sangat terbiasa membaca kode seperti itu. For-loop juga, umumnya, paling efisien ketika Anda hanya melakukan operasi kompleks apa pun yang tidak membangun daftar seperti daftar-pemahaman dan peta dioptimalkan untuk (misalnya menjumlahkan, atau membuat pohon, dll.) - setidaknya efisien dalam hal memori (tidak harus dalam hal waktu, di mana saya harapkan paling tidak merupakan faktor konstan, kecuali beberapa cegukan pengumpulan sampah patologis yang jarang terjadi)."Pythonisme"
Saya tidak suka kata "pythonic" karena saya tidak menemukan bahwa pythonic selalu anggun di mata saya. Namun demikian, map
dan filter
dan fungsi-fungsi serupa (seperti itertools
modul yang sangat berguna ) mungkin dianggap unpythonic dalam hal gaya.
Kemalasan
Dalam hal efisiensi, seperti kebanyakan konstruksi pemrograman fungsional, PETA DAPAT MENJADI LAZY , dan sebenarnya malas dengan python. Itu berarti Anda dapat melakukan ini (dalam python3 ) dan komputer Anda tidak akan kehabisan memori dan kehilangan semua data yang belum disimpan:
>>> map(str, range(10**100))
<map object at 0x2201d50>
Coba lakukan itu dengan pemahaman daftar:
>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #
Perhatikan bahwa pemahaman daftar juga inheren malas, tetapi python telah memilih untuk mengimplementasikannya sebagai tidak malas . Namun demikian, python tidak mendukung pemahaman daftar malas dalam bentuk ekspresi generator, sebagai berikut:
>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>
Anda pada dasarnya dapat menganggap [...]
sintaks sebagai meneruskan ekspresi generator ke konstruktor daftar, seperti list(x for x in range(5))
.
Contoh singkat dibikin
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))})
Pemahaman daftar tidak malas, jadi mungkin memerlukan lebih banyak memori (kecuali jika Anda menggunakan pemahaman generator). Kurung kotak [...]
sering membuat hal-hal yang jelas, terutama ketika dalam kurung. Di sisi lain, terkadang Anda berakhir seperti mengetik [x for x in...
. Selama Anda membuat variabel iterator Anda singkat, daftar pemahaman biasanya lebih jelas jika Anda tidak membuat indentasi kode Anda. Tetapi Anda selalu bisa membuat indentasi kode Anda.
print(
{x:x**2 for x in (-y for y in range(5))}
)
atau memecah hal-hal:
rangeNeg5 = (-y for y in range(5))
print(
{x:x**2 for x in rangeNeg5}
)
Perbandingan efisiensi untuk python3
map
sekarang malas:
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop ^^^^^^^^^
Karena itu jika Anda tidak akan menggunakan semua data Anda, atau tidak tahu sebelumnya berapa banyak data yang Anda butuhkan, map
di python3 (dan ekspresi generator di python2 atau python3) akan menghindari penghitungan nilainya sampai saat-saat terakhir yang diperlukan. Biasanya ini biasanya akan melebihi biaya overhead yang digunakan map
. Kelemahannya adalah ini sangat terbatas dalam python dibandingkan dengan sebagian besar bahasa fungsional: Anda hanya mendapatkan manfaat ini jika Anda mengakses data Anda dari kiri ke kanan "dalam urutan", karena ekspresi generator python hanya dapat dievaluasi urutannya x[0], x[1], x[2], ...
.
Namun katakanlah kita memiliki fungsi pra-dibuat yang f
kita inginkan map
, dan kita mengabaikan kemalasan map
dengan segera memaksa evaluasi dengannya list(...)
. Kami mendapatkan beberapa hasil yang sangat menarik:
% 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>)
Hasilnya adalah dalam bentuk AAA / BBB / CCC di mana A dilakukan dengan pada sekitar-2010 Intel workstation dengan python 3..?., Dan B dan C dilakukan dengan sekitar-2013 workstation AMD dengan python 3.2.1, dengan perangkat keras yang sangat berbeda. Hasilnya tampaknya bahwa pemahaman peta dan daftar sebanding dalam kinerja, yang paling kuat dipengaruhi oleh faktor acak lainnya. Satu-satunya hal yang dapat kami katakan adalah bahwa, anehnya, sementara kami mengharapkan daftar pemahaman [...]
untuk berkinerja lebih baik daripada ekspresi generator (...)
, map
adalah JUGA lebih efisien daripada ekspresi generator (sekali lagi dengan asumsi bahwa semua nilai dievaluasi / digunakan).
Penting untuk disadari bahwa tes-tes ini mengasumsikan fungsi yang sangat sederhana (fungsi identitas); namun ini baik-baik saja karena jika fungsinya rumit, maka overhead kinerja akan diabaikan dibandingkan dengan faktor-faktor lain dalam program. (Mungkin masih menarik untuk menguji dengan hal-hal sederhana lainnya seperti f=lambda x:x+x
)
Jika Anda ahli membaca perakitan python, Anda dapat menggunakan dis
modul untuk melihat apakah itu yang sebenarnya terjadi di balik layar:
>>> 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
Tampaknya lebih baik menggunakan [...]
sintaks daripada list(...)
. Sedihnya, map
kelasnya agak buram untuk dibongkar, tetapi kita dapat melakukannya karena dengan tes kecepatan kami.
map
dan filter
bersama dengan perpustakaan standar itertools
adalah gaya yang pada dasarnya buruk. Kecuali jika GvR benar-benar mengatakan bahwa mereka adalah kesalahan yang mengerikan atau semata-mata untuk kinerja, satu-satunya kesimpulan alami jika itu yang dikatakan "Pythonicness" adalah melupakannya sebagai hal yang bodoh ;-)
map
/ filter
adalah ide yang bagus untuk Python 3 , dan hanya pemberontakan oleh Pythonista lainnya yang menyimpannya di namespace bawaan (saat reduce
dipindahkan ke functools
). Saya pribadi tidak setuju ( map
dan filter
baik-baik saja dengan fungsi yang telah ditentukan, terutama built-in, tidak pernah menggunakannya jika lambda
diperlukan), tetapi GvR pada dasarnya menyebut mereka bukan Pythonic selama bertahun-tahun.
itertools
? Bagian yang saya kutip dari jawaban ini adalah klaim utama yang membingungkan saya. Saya tidak tahu apakah di dunia idealnya, map
dan filter
akan pindah ke itertools
(atau functools
) atau pergi sepenuhnya, tetapi yang mana yang terjadi, sekali orang mengatakan bahwa itu itertools
tidak sepenuhnya Phythonic, maka saya tidak benar-benar tahu apa "Pythonic" itu seharusnya berarti tetapi saya tidak berpikir itu bisa menjadi sesuatu yang mirip dengan "apa yang direkomendasikan GvR digunakan orang".
map
/ filter
, tidak itertools
. Pemrograman fungsional adalah Pythonic yang sempurna ( itertools
, functools
dan operator
semuanya dirancang khusus dengan pemrograman fungsional dalam pikiran, dan saya menggunakan idiom fungsional dalam Python sepanjang waktu), dan itertools
menyediakan fitur yang akan menyusahkan untuk mengimplementasikan diri Anda, Ini secara khusus map
dan filter
menjadi berlebihan dengan ekspresi generator itu membuat Guido membenci mereka. itertools
selalu baik-baik saja.
map
dan filter
bukannya daftar pemahaman.Sebuah Tujuan alasan mengapa Anda harus memilih mereka meskipun mereka tidak "Pythonic" adalah ini:
Mereka membutuhkan fungsi / lambdas sebagai argumen, yang memperkenalkan lingkup baru .
Saya telah digigit oleh ini lebih dari sekali:
for x, y in somePoints:
# (several lines of code here)
squared = [x ** 2 for x in numbers]
# Oops, x was silently overwritten!
tetapi jika saya mengatakan:
for x, y in somePoints:
# (several lines of code here)
squared = map(lambda x: x ** 2, numbers)
maka semuanya akan baik-baik saja.
Bisa dibilang saya bodoh karena menggunakan nama variabel yang sama dalam cakupan yang sama.
Bukan saya. Kode awalnya baik-baik saja - keduanya x
tidak dalam cakupan yang sama.
Hanya setelah saya memindahkan blok dalam ke bagian kode yang berbeda masalah muncul (baca: masalah selama pemeliharaan, bukan pengembangan), dan saya tidak mengharapkannya.
Ya, jika Anda tidak pernah membuat kesalahan ini, maka daftar pemahaman lebih elegan.
Tetapi dari pengalaman pribadi (dan dari melihat orang lain membuat kesalahan yang sama) Saya telah melihatnya terjadi cukup sering sehingga saya pikir itu tidak sebanding dengan rasa sakit yang harus Anda alami ketika bug ini menyusup ke dalam kode Anda.
Gunakan map
dan filter
. Mereka mencegah bug terkait lingkup yang sulit didiagnosis secara halus.
Jangan lupa untuk mempertimbangkan menggunakan imap
dan ifilter
( itertools
jika) sesuai untuk situasi Anda!
map
dan / atau filter
. Jika ada, terjemahan yang paling langsung dan logis untuk menghindari masalah Anda adalah bukan untuk map(lambda x: x ** 2, numbers)
ekspresi generator list(x ** 2 for x in numbers)
yang tidak bocor, seperti yang ditunjukkan JeromeJ. Lihatlah Mehrdad, jangan mengambil downvote secara pribadi, saya hanya sangat tidak setuju dengan alasan Anda di sini.
Sebenarnya, map
dan daftar pemahaman berperilaku sangat berbeda dalam bahasa Python 3. Lihatlah program Python 3 berikut:
def square(x):
return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
Anda mungkin mengharapkannya untuk mencetak baris "[1, 4, 9]" dua kali, tetapi ia mencetak "[1, 4, 9]" diikuti oleh "[]". Pertama kali Anda melihatnya squares
tampaknya berperilaku sebagai urutan tiga elemen, tetapi yang kedua sebagai yang kosong.
Dalam bahasa Python 2 map
mengembalikan daftar lama polos, seperti halnya pemahaman daftar lakukan di kedua bahasa. Intinya adalah bahwa nilai pengembalian map
di Python 3 (dan imap
Python 2) bukan daftar - itu adalah iterator!
Elemen-elemen tersebut dikonsumsi ketika Anda beralih pada iterator tidak seperti ketika Anda mengulangi daftar. Inilah sebabnya mengapa squares
terlihat kosong di print(list(squares))
baris terakhir .
Untuk meringkas:
map
menghasilkan struktur data, bukan iterator. Tapi mungkin iterator malas lebih mudah daripada struktur data malas. Bahan untuk dipikirkan. Terima kasih @MnZrK
Saya menemukan daftar pemahaman umumnya lebih ekspresif dari apa yang saya coba lakukan daripada map
- mereka berdua menyelesaikannya, tetapi yang pertama menghemat beban mental mencoba memahami apa yang bisa menjadi lambda
ekspresi yang kompleks .
Ada juga wawancara di luar sana (saya tidak dapat menemukannya secara langsung) di mana Guido mencantumkan lambda
fungsi fungsional sebagai hal yang paling disesalnya tentang penerimaan ke Python, sehingga Anda dapat membuat argumen bahwa mereka tidak Pythonic berdasarkan dari itu.
const
kata kunci dalam C ++ adalah kemenangan besar di sepanjang baris ini.
lambda
dibuat sangat timpang (tidak ada pernyataan ..) sehingga sulit digunakan dan dibatasi.
Ini ada satu kemungkinan kasus:
map(lambda op1,op2: op1*op2, list1, list2)
melawan:
[op1*op2 for op1,op2 in zip(list1,list2)]
Saya menduga zip () adalah overhead yang tidak menguntungkan dan tidak perlu yang harus Anda nikmati jika Anda bersikeras menggunakan pemahaman daftar alih-alih peta. Akan lebih bagus jika seseorang mengklarifikasi hal ini apakah secara afirmatif atau negatif.
zip
malas dengan menggunakanitertools.izip
map(operator.mul, list1, list2)
. Ekspresi sisi kiri yang sangat sederhana inilah yang membuat pemahaman menjadi kikuk.
Jika Anda berencana untuk menulis kode asinkron, paralel, atau terdistribusi, Anda mungkin akan lebih suka map
daripada pemahaman daftar - karena sebagian besar paket asinkron, paralel, atau terdistribusi menyediakan map
fungsi untuk membebani python yang berlebihan map
. Kemudian dengan meneruskan map
fungsi yang sesuai ke kode Anda yang lain, Anda mungkin tidak perlu memodifikasi kode serial asli Anda agar dapat berjalan secara paralel (dll).
Jadi karena Python 3, map()
adalah iterator, Anda perlu mengingat apa yang Anda butuhkan: iterator atau list
objek.
Seperti @AlexMartelli telah sebutkan , map()
lebih cepat dari daftar pemahaman hanya jika Anda tidak menggunakan lambda
fungsi.
Saya akan menyajikan beberapa perbandingan waktu.
Python 3.5.2 dan CPython
Saya telah menggunakan notebook Jupiter dan terutama %timeit
built-in magic command
Measurements : s == 1000 ms == 1000 * 1000 µs = 1000 * 1000 * 1000 ns
Mendirikan:
x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
Fungsi bawaan:
%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
fungsi:
%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
Ada juga yang namanya ekspresi generator, lihat PEP-0289 . Jadi saya pikir akan bermanfaat untuk menambahkannya sebagai perbandingan
%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
objek:Gunakan pemahaman daftar jika itu fungsi khusus, gunakan list(map())
jika ada fungsi builtin
list
objek, Anda hanya perlu objek iterable:Selalu gunakan map()
!
Saya menjalankan tes cepat membandingkan tiga metode untuk memohon metode objek. Perbedaan waktu, dalam hal ini, dapat diabaikan dan merupakan masalah fungsi yang dimaksud (lihat tanggapan @Alex Martelli ). Di sini, saya melihat metode berikut:
# 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]
Saya melihat daftar (disimpan dalam variabel vals
) dari kedua bilangan bulat (Python int
) dan angka floating point (Python float
) untuk meningkatkan ukuran daftar. Kelas dummy berikut DummyNum
dipertimbangkan:
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
Secara khusus, add
metode. The __slots__
atribut adalah optimasi sederhana dengan Python untuk menentukan total memori yang dibutuhkan oleh kelas (atribut), mengurangi ukuran memori. Berikut adalah plot yang dihasilkan.
Seperti yang dinyatakan sebelumnya, teknik yang digunakan membuat perbedaan minimal dan Anda harus kode dengan cara yang paling mudah dibaca oleh Anda, atau dalam keadaan tertentu. Dalam hal ini, pemahaman daftar ( map_comprehension
teknik) adalah yang tercepat untuk kedua jenis penambahan dalam suatu objek, terutama dengan daftar yang lebih pendek.
Kunjungi pastebin ini untuk sumber yang digunakan untuk menghasilkan plot dan data.
map
lebih cepat hanya jika fungsinya dipanggil dengan cara yang sama persis (yaitu [*map(f, vals)]
vs. [f(x) for x in vals]
). Jadi list(map(methodcaller("add"), vals))
lebih cepat daripada [methodcaller("add")(x) for x in vals]
. map
mungkin tidak lebih cepat ketika rekan perulangan menggunakan metode panggilan yang berbeda yang dapat menghindari beberapa overhead (mis. x.add()
menghindari methodcaller
atau ekspresi overhead lambda). Untuk kasus uji khusus ini, [*map(DummyNum.add, vals)]
akan lebih cepat (karena DummyNum.add(x)
dan x.add()
pada dasarnya memiliki kinerja yang sama).
list()
panggilan eksplisit sedikit lebih lambat dari daftar. Untuk perbandingan yang adil, Anda perlu menulis [*map(...)]
.
list()
panggilan meningkat di atas kepala. Seharusnya menghabiskan lebih banyak waktu membaca jawaban. Saya akan menjalankan kembali tes ini untuk perbandingan yang adil, betapapun kecilnya perbedaan yang mungkin terjadi.
Saya menganggap bahwa cara paling Pythonic adalah dengan menggunakan daftar pemahaman daripada map
dan filter
. Alasannya adalah bahwa pemahaman daftar lebih jelas daripada map
dan 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
Seperti yang Anda lihat, pemahaman tidak memerlukan lambda
ekspresi tambahan sebagai map
kebutuhan. Selain itu, pemahaman juga memungkinkan penyaringan dengan mudah, sementara map
mengharuskan filter
penyaringan.
Saya mencoba kode dengan @ alex-martelli tetapi menemukan beberapa perbedaan
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
peta membutuhkan jumlah waktu yang sama bahkan untuk rentang yang sangat besar saat menggunakan pemahaman daftar membutuhkan banyak waktu seperti terbukti dari kode saya. Jadi selain dianggap "unpythonic", saya belum menghadapi masalah kinerja yang berkaitan dengan penggunaan peta.
map
mengembalikan daftar. Dalam Python 3, map
dievaluasi malas, jadi hanya memanggil map
tidak menghitung elemen daftar baru, maka mengapa Anda mendapatkan waktu sesingkat itu.