>>> range(1,11)
daje Ci
[1,2,3,4,5,6,7,8,9,10]
Dlaczego nie 1-11?
Czy po prostu postanowili zrobić to w ten sposób losowo, czy ma to jakąś wartość, której nie widzę?
range()
ma sens znacznie częściej
>>> range(1,11)
daje Ci
[1,2,3,4,5,6,7,8,9,10]
Dlaczego nie 1-11?
Czy po prostu postanowili zrobić to w ten sposób losowo, czy ma to jakąś wartość, której nie widzę?
range()
ma sens znacznie częściej
Odpowiedzi:
Ponieważ częstsze jest wywoływanie, range(0, 10)
które zwraca [0,1,2,3,4,5,6,7,8,9]
10 elementów, które są równelen(range(0, 10))
. Pamiętaj, że programiści wolą indeksowanie oparte na 0.
Weź również pod uwagę następujący wspólny fragment kodu:
for i in range(len(li)):
pass
Czy widzisz, że gdyby range()
doszło dokładnie do len(li)
tego, byłoby to problematyczne? Programista musiałby wyraźnie odjąć 1. Wynika to również wspólny trend programistów preferując for(int i = 0; i < 10; i++)
nad for(int i = 0; i <= 9; i++)
.
Jeśli często wywołujesz zakres z początkiem 1, możesz chcieć zdefiniować własną funkcję:
>>> def range1(start, end):
... return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range(start, count)
?
range(10)
jest równa range(0, 10)
.
range1
nie będzie działać z zakresami, które mają inny rozmiar kroku niż 1
.
for i in range(len(li)):
jest raczej antypatternem. Należy użyć enumerate
.
Chociaż istnieją tutaj pewne użyteczne wyjaśnienia algorytmiczne, myślę, że może pomóc dodanie prostego rozumowania w „prawdziwym życiu”, dlaczego działa to w ten sposób, co znalazłem przydatne, gdy przedstawiłem ten temat młodym nowicjuszom:
Przy czymś takim jak „zakres (1,10)” może pojawić się zamieszanie w wyniku myślenia, że para parametrów reprezentuje „początek i koniec”.
W rzeczywistości zaczyna się i „zatrzymuje”.
Teraz gdyby tak było wartości „koniec”, a następnie, tak, możesz spodziewać się, że liczba będzie uwzględniona jako ostatecznego wejścia w sekwencji. Ale to nie jest „koniec”.
Inni błędnie nazywają ten parametr „count”, ponieważ jeśli użyjesz tylko „range (n)”, wówczas oczywiście iteruje się „n” razy. Ta logika ulega awarii po dodaniu parametru początkowego.
Kluczową kwestią jest zapamiętanie jego nazwy: „ stop ”. Oznacza to, że w tym momencie iteracja natychmiast się zatrzyma. Nie po tym punkcie.
Tak więc, chociaż „start” rzeczywiście reprezentuje pierwszą wartość, którą należy uwzględnić, to po osiągnięciu wartości „stop” „pęka”, a nie kontynuuje przetwarzanie „również tej” przed zatrzymaniem.
Jedną z analogii, którą wykorzystałem, tłumacząc to dzieciom, jest to, że, jak na ironię, lepiej się zachowuje niż dzieci! Nie kończy się po tym, jak powinien - zatrzymuje się natychmiast, nie kończąc tego, co robił. (Dostają to;))
Kolejna analogia - kiedy prowadzisz samochód, nie mijamy znaku stop / ustępowania / „ustąp” i kończy się to, że siedzisz gdzieś obok lub za samochodem. Technicznie rzecz biorąc, nadal nie osiągnąłeś tego, kiedy przestałeś. Nie jest uwzględnione w „rzeczach, które przekazałeś podczas podróży”.
Mam nadzieję, że niektóre z nich pomogą wyjaśnić Pythonitos / Pythonitas!
Działa dobrze w połączeniu z indeksowaniem zerowym i len()
. Na przykład, jeśli masz 10 pozycji na liście x
, są one ponumerowane 0–9. range(len(x))
daje ci 0-9.
Oczywiście, ludzie będą wam to bardziej pythonowy zrobić for item in x
lub for index, item in enumerate(x)
zamiast for i in range(len(x))
.
Krojenie również działa w ten sposób: foo[1:4]
to pozycje 1-3 foo
(pamiętając, że pozycja 1 jest tak naprawdę drugą pozycją ze względu na indeksowanie zerowe). Aby zachować spójność, oba powinny działać w ten sam sposób.
Myślę o tym jako: „pierwszy numer, którego chcesz, a następnie pierwszy numer, którego nie chcesz”. Jeśli chcesz 1-10, pierwszą liczbą, której nie chcesz, jest 11, więc jest range(1, 11)
.
Jeśli w konkretnej aplikacji staje się nieporęczny, wystarczy napisać małą funkcję pomocniczą, która dodaje 1 do indeksu końcowego i wywołań range()
.
w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1];
def full_range(start,stop): return range(start,stop+1) ## helper function
for index, item in enumerate(x)
aby uniknąć zamieszania
Jest także przydatny do dzielenia zakresów; range(a,b)
można podzielić na range(a, x)
a range(x, b)
, natomiast z zakresu integracyjnego byś napisać albo x-1
albo x+1
. Chociaż rzadko trzeba dzielić zakresy, często dzielisz listy, co jest jednym z powodów, dla których krojenie listy l[a:b]
zawiera a-ty element, ale nie b-ty. Zatem range
posiadanie tej samej właściwości sprawia, że jest ładnie spójna.
Długość zakresu to górna wartość minus dolna wartość.
Jest bardzo podobny do czegoś takiego:
for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}
w języku C.
Podobnie jak zakres Ruby:
1...11 #this is a range from 1 to 10
Jednak Ruby rozpoznaje, że wiele razy będziesz chciał dołączyć wartość końcową i oferuje alternatywną składnię:
1..10 #this is also a range from 1 to 10
1..10
vs 1...10
będąc ciężko rozróżnić podczas czytania kodu!
Zasadniczo w pythonie range(n)
iteruje się n
czasy, które mają charakter wyłączny, dlatego nie podaje ostatniej wartości podczas drukowania, możemy stworzyć funkcję, która daje wartość włączającą, co oznacza, że wypisze również ostatnią wartość wymienioną w zakresie.
def main():
for i in inclusive_range(25):
print(i, sep=" ")
def inclusive_range(*args):
numargs = len(args)
if numargs == 0:
raise TypeError("you need to write at least a value")
elif numargs == 1:
stop = args[0]
start = 0
step = 1
elif numargs == 2:
(start, stop) = args
step = 1
elif numargs == 3:
(start, stop, step) = args
else:
raise TypeError("Inclusive range was expected at most 3 arguments,got {}".format(numargs))
i = start
while i <= stop:
yield i
i += step
if __name__ == "__main__":
main()
Rozważ kod
for i in range(10):
print "You'll see this 10 times", i
Chodzi o to, że otrzymujesz listę długości y-x
, którą możesz (jak widać powyżej) iterować.
Przeczytaj dokumentację Pythona dotyczącą zakresu - uważają oni, że iteracja pętli for jest podstawowym przypadkiem użycia.
W wielu przypadkach wygodniej jest rozumować.
Zasadniczo moglibyśmy myśleć o zakresie jako odstępie między start
i end
. Jeśli start <= end
odstęp między nimi wynosi end - start
. Gdyby len
faktycznie zdefiniowano jako długość, miałbyś:
len(range(start, end)) == start - end
Liczymy jednak liczby całkowite zawarte w zakresie, zamiast mierzyć długość przedziału. Aby powyższa właściwość była prawdziwa, powinniśmy uwzględnić jeden z punktów końcowych, a drugi wykluczyć.
Dodanie step
parametru jest jak wprowadzenie jednostki długości. W takim przypadku można się spodziewać
len(range(start, end, step)) == (start - end) / step
na długość. Aby uzyskać liczbę, wystarczy użyć podziału na liczby całkowite.