Neden `1000000000000000 aralığı(1000000000000001) bu kadar hızlı Python 3'te mi?
Aslında an object type in Python 3, range()
işlevi, sinek, jeneratör benzer içeriğini oluşturur anladığım kadarıyla.
Bu durumda, burada beklenen aşağıdaki satırı için bir aşırı miktarda zaman, çünkü sipariş olup olmadığını belirlemek için 1 katrilyon ise Aralık, katrilyon değerleri ... oluşturulabilir:
1000000000000000 in range(1000000000000001)
Ayrıca: kaç tane ben eklemek olursa olsun, hesaplama daha fazla veya daha az süresi (temel olarak) anlık aynı miktarda alır gibi görünüyor.
Ayrıca bu gibi şeyler denedim, ama hesaplama hala neredeyse anında
1000000000000000000000 in range(0,1000000000000000000001,10) # count by tens
Eğer kendi aralığı benim işlevi yerine getirmeye çalıştım, sonuç çok güzel!!
def my_crappy_range(N):
i = 0
while i < N:
yield i
i = 1
return
Her şey çok hızlı yapar range()
nesne kaputun altında ne işi var?
EDİT: Bu tahmin ettiğimden çok daha farklı bir konu oldu - range()
optimizasyon arkasında tarihin biraz var gibi görünüyor.
Martijn Pieters' answer kendi bütünlüğü için seçildi, ama aynı zamanda range
tam teşekküllü olmak için ne anlama geldiğini iyi bir tartışma için abarnert's first answer bkzsıraPython 3 ve bazı bilgi/uyarı __contains__
potansiyel tutarsızlık ile ilgili Python uygulamaları optimizasyon fonksiyonu. abarnert's other answer biraz daha detaya girer ve bu Python 3'te optimizasyon arkasındaki tarihi (ve Python 2 xrange
optimizasyon eksikliği) ilgilenenler için bağlantılar sağlar. Cevap by poke by wim ilgilenenler için C kaynak kodu ve açıklamalar ilgili sağlayabilir.
CEVAP
3 range()
Python nesne sayıları hemen üretmek değil; sayılar üreten akıllı bir sıra nesnesitalep üzerine. Başlat, Durdur ve adım değerleri vardır, sonra nesne üzerinde yineleme gibi bir sonraki tamsayı her yineleme hesaplanır.
Nesne de object.__contains__
hook ve . uygular ^em>hesaplarnumaranız varsa yelpazesini bir parçası. Hesaplama O(1) sabit zaman bir operasyon. Hiçbir zaman aralığında mümkün olan tüm tamsayılar taramak için bir ihtiyaç vardır.
Avantaj
range
tipi bir düzenlilist
tuple
bir aralık nesnesi hep aynı (küçük) bir bellek miktarı, boyutu ne olursa olsun aralığını temsil eder (olarak sadece depolarstart
,stop
step
değerleri, hesaplama bireysel öğeleri ve alt aralıklar gerektiği gibi).
Yani en azından range()
nesne yapar:
class my_range(object):
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = start, stop, step
if step < 0:
lo, hi = stop, start
else:
lo, hi = start, stop
self.length = ((hi - lo - 1) // abs(step)) 1
def __iter__(self):
current = self.start
if self.step < 0:
while current > self.stop:
yield current
current = self.step
else:
while current < self.stop:
yield current
current = self.step
def __len__(self):
return self.length
def __getitem__(self, i):
if 0 <= i < self.length:
return self.start i * self.step
raise IndexError('Index out of range: {}'.format(i))
def __contains__(self, num):
if self.step < 0:
if not (self.stop < num <= self.start):
return False
else:
if not (self.start <= num < self.stop):
return False
return (num - self.start) % self.step == 0
Bu hala eksik bazı şeyler bu bir gerçek range()
destekler (gibi .index()
.count()
yöntem, karma, eşitlik testi, ya da Dilimleme), ama iyi bir fikir.
Ben de basitleştirilmiş __contains__
uygulama için sadece odaklanmak tamsayı testleri; eğer gerçek bir range()
nesnesi olmayan bir tamsayı değeri (alt sınıflar da dahil olmak üzere int
), yavaş tarama başlatılan görmek için bir maç, sadece bir çevreleme test karşı bir liste tüm bulunan değerler. Bu sadece tamsayılar ile eşitliği test destek oluyor ama tamsayı aritmetik destek vermesi beklenmiyor da diğer sayısal türlerini desteklemek için devam etmek için yapıldı. Çevreleme testi uygulayan Python issue orijinal bakın.