Du vill loopa igenom fem kort i en lista och skriver range(1, 5), men det sista kortet hoppas över. I Python skapar range() normalt talen fram till, men inte inklusive, stoppvärdet, även om stegriktningen kan ändra vad som händer.
Kom ihåg start, stopp och steg
range(stop)börjar på 0 och slutar före stoppvärdet.range(start, stop)låter dig välja startvärde.range(start, stop, step)styr hur stort hoppet mellan talen är.- Stoppvärdet ingår inte, och steget måste gå i riktning mot stoppet.
range()är inte en lista, även om du kan loopa över den som en.
Stoppvärdet ligger utanför sekvensen
Föreställ dig att du numrerar fem bilder från noll och vill skapa index för dem. Då passar range(5): det ger 0, 1, 2, 3, 4, alltså exakt de fem giltiga indexen. Det sista talet är alltid före stoppvärdet.
Jag tycker att regeln blir lättare att använda när du tänker på stoppvärdet som en gräns, inte som det sista talet. Samma princip fungerar för dels sekvenser och dels loopar: range(2, 6) ger 2, 3, 4, 5. Python-dokumentationen beskriver detta som ett intervall där start ingår och stopp inte gör det.
Välj argument efter vad loopen ska göra
En liten ändring i argumenten kan förändra hela serien. Funktionen tar upp till tre heltalsargument: start, stopp och steg. Om du utelämnar start börjar sekvensen vid noll, och om du utelämnar steg används ett steg på ett.
| Kod | Tal som skapas | Passar när |
|---|---|---|
range(4) | 0, 1, 2, 3 | Du vill upprepa något fyra gånger eller skapa giltiga index. |
range(3, 7) | 3, 4, 5, 6 | Du vill börja på ett annat tal än noll. |
range(1, 10, 2) | 1, 3, 5, 7, 9 | Du vill hoppa över vartannat heltal. |
range(8, 2, -2) | 8, 6, 4 | Du vill räkna nedåt med jämna hopp. |
Negativt steg är användbart när du vill gå bakåt, men bara om startvärdet ligger över stoppvärdet. Med ett positivt steg och en högre start än stopp blir resultatet tomt. Riktningen måste stämma med stegets tecken.
För att räkna till och med ett tal flyttar du stoppgränsen
Om en numrerad lista ska innehålla talen 1 till 5 skriver du range(1, 6), inte range(1, 5). Den senare koden stannar före fem och ger bara fyra tal. Det här är ett typiskt ställe för ett så kallat off-by-one-fel, där en loop körs en gång för få eller en gång för mycket.
En användbar tumregel är enkel: om sista önskade talet ska ingå, använd nästa heltal som stopp. Ska du exempelvis bearbeta rader med index från 0 till 99 använder du range(100). Den öppna slutgränsen gör också att antalet heltal i range(100) stämmer med antalet index i en lista med 100 element.
Kontrollera steg och datatyp när resultatet blir tomt eller felar
En tom loop betyder inte nödvändigtvis att Python har fastnat. Ofta pekar steget åt fel håll: range(5, 1) ger ingen serie, eftersom standardsteget är positivt medan startvärdet redan är större än stoppvärdet. Byt till ett negativt steg om du vill räkna nedåt.
| Situation | Trolig orsak | Gör så här |
|---|---|---|
range(5, 1) ger inga tal | Standardsteget räknar uppåt, men stoppvärdet ligger lägre. | Använd exempelvis range(5, 1, -1). |
range(1, 8, 0) ger ett fel | Ett steg på noll kan inte ta serien framåt eller bakåt. | Välj ett positivt eller negativt heltal som steg. |
range(2.5) ger ett fel | range() kräver heltalsargument. | Bestäm hur du vill hantera decimaltal och använd en passande metod. |
| En loop missar sista indexet | Stoppvärdet ingår inte. | För en lista med fem element är range(5) rätt för index 0 till 4. |
Om du behöver tal med decimalsteg, till exempel värden från 0 till 1 i tiondelar, passar den inbyggda range() inte direkt. Tvinga inte in decimaltal i funktionen; valet av verktyg beror på om du vill bygga en numerisk array eller bara stega mellan heltal.
En range är inte en lista, och det spelar roll vid stora loopar
range(1000000) skapar inte en miljon lagrade heltal på samma sätt som list(range(1000000)) gör. Ett range-objekt håller reda på start, stopp och steg och räknar fram värdena när de behövs. Python-dokumentationen anger att objektets minnesåtgång är konstant oavsett hur lång sekvensen är.
Det gör range() till ett smidigt val för loopar över många heltal. Men om du behöver ändra ordning på värdena, lägga till element eller visa hela serien som en lista, behöver du skapa en separat lista. Konvertera därför bara med list() när du faktiskt behöver listans egenskaper.
För numeriska arrayer med jämnt fördelade värden finns också NumPys arange(). Den returnerar en NumPy-array och kan ta decimala steg, medan flyttalsavrundning kan ge oväntade gränser; NumPys dokumentation rekommenderar därför ofta linspace() när antalet punkter och ändpunkterna ska styras noggrant.
Testa gränsen innan du kör hela loopen
När en loop beter sig oväntat, skriv ut en liten sekvens först: print(list(range(start, stop, step))). Då syns det direkt om stoppvärdet saknas, om serien är tom eller om steget går åt fel håll.
För vanliga heltalsloopar är grundvalet ändå rakt: börja med range(n) för n index eller upprepningar, och lägg till start och steg när uppgiften kräver det. Tänk stoppgräns, inte sista värde, så slipper du det borttappade femte kortet.