Baru-baru ini saya mulai menggunakan Python3 dan kurangnya xrange sakit.
Contoh sederhana:
1) Python2:
from time import time as t
def count():
st = t()
[x for x in xrange(10000000) if x%4 == 0]
et = t()
print et-st
count()
2) Python3:
from time import time as t
def xrange(x):
return iter(range(x))
def count():
st = t()
[x for x in xrange(10000000) if x%4 == 0]
et = t()
print (et-st)
count()
Hasilnya, masing-masing:
1) 1.53888392448 2) 3.215819835662842
Mengapa demikian? Maksudku, mengapa xrange dihapus? Ini alat yang luar biasa untuk dipelajari. Untuk pemula, sama seperti saya, seperti kita semua ada di beberapa titik. Mengapa menghapusnya? Adakah yang bisa mengarahkan saya ke PEP yang tepat, saya tidak dapat menemukannya.
Bersulang.
python
python-3.x
pep
xrange
catalesia
sumber
sumber
range
dalam Python 3.x berasalxrange
dari Python 2.x. Sebenarnya Python 2.xrange
yang dihapus.time
. Selain menjadi lebih mudah digunakan dan lebih sulit untuk salah, dan mengulangi tes untuk Anda,timeit
mengurus semua hal yang Anda tidak akan ingat, atau bahkan tahu bagaimana, untuk mengurus (seperti menonaktifkan GC), dan dapat menggunakan Jam dengan resolusi ribuan kali lebih baik.range
padax%4 == 0
? Mengapa tidak hanya mengujilist(xrange())
vslist(range())
, jadi ada pekerjaan luar yang sesedikit mungkin? (Misalnya, bagaimana Anda tahu 3.x tidak melakukanx%4
lebih lambat?) Untuk itu, mengapa Anda membangun besarlist
, yang melibatkan banyak alokasi memori (yang, selain lambat, juga sangat bervariasi) ?iter(range)
berlebihan.list(range(..))
. Itu setara dengan rentang python 2. Atau mengatakannya dengan cara lain: xrange telah diubah jangkauannya, karena ini adalah default yang lebih baik; tidak perlu memiliki keduanya, lakukanlist(range)
jika Anda benar-benar membutuhkan daftar. .Jawaban:
Beberapa pengukuran kinerja, menggunakan
timeit
alih-alih mencoba melakukannya secara manualtime
.Pertama, Apple 2.7.2 64-bit:
Sekarang, python.org 3.3.0 64-bit:
Rupanya, 3.x
range
benar-benar sedikit lebih lambat dari 2.xxrange
. Dan fungsi OPxrange
tidak ada hubungannya dengan itu. (Tidak mengherankan, karena panggilan satu kali ke__iter__
slot tidak akan terlihat di antara 10.000.000 panggilan untuk apa pun yang terjadi dalam loop, tetapi seseorang mengemukakannya sebagai suatu kemungkinan.)Tapi ini hanya 30% lebih lambat. Bagaimana OP mendapat 2x lebih lambat? Nah, jika saya mengulangi tes yang sama dengan Python 32-bit, saya mendapatkan 1,58 vs 3,12. Jadi tebakan saya adalah bahwa ini adalah kasus lain di mana 3.x telah dioptimalkan untuk kinerja 64-bit dengan cara yang menyakitkan 32-bit.
Tetapi apakah itu benar-benar penting? Lihat ini, dengan 3.3.0 64-bit lagi:
Jadi, membangun
list
membutuhkan lebih dari dua kali lebih lama dari seluruh iterasi.Dan untuk "menghabiskan lebih banyak sumber daya daripada Python 2.6+", dari pengujian saya, sepertinya 3.x
range
persis ukuran yang sama dengan 2.xxrange
—dan, bahkan jika itu 10x lebih besar, membangun daftar yang tidak perlu masih sekitar 10.000.000x lebih dari masalah daripada apa pun rentang iterasi mungkin bisa dilakukan.Dan bagaimana dengan
for
loop eksplisit, bukan loop C di dalamdeque
?Jadi, hampir sebanyak waktu yang terbuang dalam
for
pernyataan seperti pada pekerjaan aktual iterasirange
.Jika Anda khawatir tentang mengoptimalkan iterasi objek rentang, Anda mungkin mencari di tempat yang salah.
Sementara itu, Anda terus bertanya mengapa
xrange
dihapus, tidak peduli berapa kali orang mengatakan hal yang sama kepada Anda, tetapi saya akan mengulanginya lagi: Tidak dihapus: diubah namanya menjadirange
, dan 2.xrange
adalah yang dihapus.Berikut beberapa bukti bahwa
range
objek 3.3 adalah turunan langsung darixrange
objek 2.x (dan bukan darirange
fungsi 2.x ): sumber ke 3.3range
dan 2.7xrange
. Anda bahkan dapat melihat riwayat perubahan (terkait dengan, saya percaya, perubahan yang menggantikan instance terakhir dari string "xrange" di mana saja dalam file).Jadi, mengapa lebih lambat?
Pertama, mereka telah menambahkan banyak fitur baru. Untuk yang lain, mereka telah melakukan semua jenis perubahan di semua tempat (terutama di dalam iterasi) yang memiliki efek samping kecil. Dan ada banyak pekerjaan untuk secara dramatis mengoptimalkan berbagai kasus penting, bahkan jika kadang-kadang sedikit pesimis kasus yang kurang penting. Tambahkan semua ini, dan saya tidak terkejut bahwa iterasi
range
secepat mungkin sekarang sedikit lebih lambat. Ini adalah salah satu dari kasus-kasus yang kurang penting yang tidak akan pernah dipedulikan oleh siapa pun. Tidak ada yang mungkin memiliki kasus penggunaan nyata di mana perbedaan kinerja ini adalah hotspot dalam kode mereka.sumber
range
. Therange
objek dalam 3.3 adalah keturunan langsung darixrange
objek di 2.7, bukan darirange
fungsi di 2,7. Ini seperti meminta sementaraitertools.imap
dihapus untuk mendukungmap
. Tidak ada jawaban, karena tidak ada yang terjadi.range
sementara tidak melakukan hal lain.Berbagai Python3 ini adalah xrange python2 ini. Tidak perlu membungkus iter di sekitarnya. Untuk mendapatkan daftar aktual di Python3, Anda harus menggunakan
list(range(...))
Jika Anda menginginkan sesuatu yang berfungsi dengan Python2 dan Python3, coba ini
sumber
range
danxrange
akan berperilaku berbeda. Tidak cukup untuk melakukan ini, kita juga harus memastikan untuk tidak menganggap bahwarange
mengembalikan daftar (seperti dalam python 2).futurize
alat untuk secara otomatis mengonversi kode sumber Anda: python-future.org/…range
Jenis Python 3 berfungsi seperti halnya Python 2xrange
. Saya tidak yakin mengapa Anda melihat perlambatan, karena iterator yang dikembalikan olehxrange
fungsi Anda adalah persis apa yang akan Anda dapatkan jika Anda mengulanginyarange
secara langsung.Saya tidak dapat mereproduksi perlambatan pada sistem saya. Inilah cara saya menguji:
Python 2, dengan
xrange
:Python 3, dengan
range
sedikit lebih cepat:Baru-baru ini saya mengetahui bahwa
range
tipe Python 3 memiliki beberapa fitur rapi lainnya, seperti dukungan untuk slicing:range(10,100,2)[5:25:5]
isrange(20, 60, 10)
!sumber
xrange
berkali-kali, atau apakah itu dilakukan hanya sekali?xrange
itu tidak dihapus, hanya berganti nama .range
, sejauh yang saya ketahui, adalah waktu yang konstan__contains__
. Pemula biasa menulis300000 in xrange(1000000)
dan menyebabkannya mengulangi keseluruhanxrange
(atau setidaknya 30% pertama dari itu), jadi kami harus menjelaskan mengapa itu adalah ide yang buruk, meskipun itu terlihat sangat pythonic. Sekarang, itu adalah pythonic.Salah satu cara untuk memperbaiki kode python2 Anda adalah:
sumber
range = xrange
seperti yang di komentar oleh @John La Royxrange = range
xrange dari Python 2 adalah generator dan mengimplementasikan iterator sementara range hanyalah sebuah fungsi. Dalam Python3 saya tidak tahu mengapa dijatuhkan xrange.
sumber
range()
adalah setara dengan PY2xrange()
. Dan dengan demikian di PY3xrange()
berlebihan.comp: ~ $ python Python 2.7.6 (default, 22 Jun 2015, 17:58:13) [GCC 4.8.2] di linux2
5.656799077987671
5.579368829727173
21.54827117919922
22.014557123184204
Dengan angka timeit = 1 param:
0.2245171070098877
0.10750913619995117
comp: ~ $ python3 Python 3.4.3 (default, 14 Okt 2015, 20:28:29) [GCC 4.8.4] di linux
9.113872020003328
9.07014398300089
Dengan angka timeit = 1,2,3,4 param bekerja cepat dan dengan cara linear:
0,09329321900440846
0.18501482300052885
0,2703447980020428
0.36209142999723554
Jadi sepertinya jika kita mengukur 1 siklus putaran berjalan seperti timeit.timeit ("[x untuk x dalam kisaran (1000000) jika x% 4]", angka = 1) (seperti yang kita gunakan dalam kode nyata) python3 bekerja cukup cepat, tetapi dalam loop berulang python 2 xrange () menang dalam kecepatan terhadap range () dari python 3.
sumber