Schleifen von 1 bis unendlich in Python

74

In C würde ich Folgendes tun:

int i;
for (i = 0;; i++)
  if (thereIsAReasonToBreak(i))
    break;

Wie kann ich in Python etwas Ähnliches erreichen?

teh_senaus
quelle
2
Ich bin kein Python-Experte, aber while (true): if reasonneeded(i) break i = i+1sollte funktionieren?
HKF
2
mögliches Duplikat von Python unbegrenzt xrange ()
wim
In C würde dies einen Überlauf verursachen und nicht zu "unendlich" gehen
Philipp
1
Sollte der Titel dieser Frage nicht in "Schleifen von 0 nach unendlich in Python" geändert werden? Sie versuchen einfach, ein "Unendliches range" zu haben, damit Sie vermeiden könnenwhile True: i += 1
etwas Etwas

Antworten:

130

Verwenden von itertools.count:

import itertools
for i in itertools.count(start=1):
    if there_is_a_reason_to_break(i):
        break

In Python 2 range()und xrange()waren beschränkt auf sys.maxsize. In Python 3 range()kann es viel höher gehen, wenn auch nicht bis ins Unendliche:

import sys
for i in range(sys.maxsize**10):  # you could go even higher if you really want
    if there_is_a_reason_to_break(i):
        break

Es ist also wahrscheinlich am besten zu verwenden count().

John La Rooy
quelle
10
Dies spielt auch gut mit takewhile:for x in takewhile(thereIsAReasonToContinue, count()):
Georg
Für mich for i in range(sys.maxint)bricht mit einem MemoryError. Sie haben auch erwähnt, xrange()was funktioniert.
Scai
3
@scai rangeersetzt in Python3 Python2 xrange. In Python2 rangewird eine tatsächliche Liste von Ints erstellt und zurückgegeben. Sie werden nicht genug RAM für eine so große Liste haben
John La Rooy
17
def to_infinity():
    index = 0
    while True:
        yield index
        index += 1

for i in to_infinity():
    if i > 10:
        break
Spicavigo
quelle
9

Einfachste und beste:

i = 0
while not there_is_reason_to_break(i):
    # some code here
    i += 1

Es kann verlockend sein, die nächstgelegene Analogie zum in Python möglichen C-Code zu wählen:

from itertools import count

for i in count():
    if thereIsAReasonToBreak(i):
        break

Beachten Sie jedoch, dass das Ändern iden Ablauf der Schleife nicht wie in C beeinflusst. Daher ist die Verwendung einer whileSchleife die geeignetere Wahl, um diesen C-Code nach Python zu portieren.

wim
quelle
4

Wiederholung des Kommentars von thg435:

from itertools import takewhile, count

def thereIsAReasonToContinue(i):
    return not thereIsAReasonToBreak(i)

for i in takewhile(thereIsAReasonToContinue, count()):
    pass # or something else

Oder vielleicht prägnanter:

from itertools import takewhile, count

for i in takewhile(lambda x : not thereIsAReasonToBreak(x), count()):
    pass # or something else

takewhileimitiert eine "gut erzogene" C for-Schleife: Sie haben eine Fortsetzungsbedingung, aber Sie haben einen Generator anstelle eines beliebigen Ausdrucks. Es gibt Dinge, die Sie in einer C for-Schleife tun können, die sich "schlecht verhalten", z. B. das Ändern iim Schleifenkörper. Es ist auch möglich, diese zu imitieren takewhile, wenn der Generator eine lokale Variable schließt i, mit der Sie sich dann anlegen. In gewisser Weise macht die Definition dieses Abschlusses besonders deutlich, dass Sie etwas tun, das möglicherweise mit Ihrer Kontrollstruktur verwirrt.

Steve Jessop
quelle
2
def infinity():
    i=0
    while True:
        i+=1
        yield i


for i in infinity():
    if there_is_a_reason_to_break(i):
        break
rekinyz
quelle
1
Danke, das war es, wonach ich gesucht habe. Sauberster und schönster Ansatz imo.
Marcel Braasch
Ja, sehr sauber, ich hatte die Leistung yieldanderer als für Lazy-Sequence-Generatoren nicht ganz ausgeschöpft , aber ein Freund hat sie kürzlich verwendet, um eine pushd/popdFunktion bereitzustellen , ohne einen expliziten Stack verwalten zu müssen. Sehr klug war es.
paxdiablo
2

Wenn du das in C machst, ist dein Urteil dort genauso trübe wie in Python :-)

Für eine Schleife, die bei einer einfachen Bedingungsprüfung zu Beginn jeder Iteration beendet wird, ist es üblicher (und meiner Meinung nach klarer), dies nur im Schleifenkonstrukt selbst zu tun. Mit anderen Worten, so etwas wie (wenn Sie inach dem Ende der Schleife benötigen ):

int i = 0;
while (! thereIsAReasonToBreak(i)) {
    // do something
    i++;
}

oder (wenn nur die Schleife ierfasst werden kann ):

for (int i = 0; ! thereIsAReasonToBreak(i); ++i) {
    // do something
}

Das würde sich in das Python-Äquivalent übersetzen lassen:

i = 0
while not there_is_a_reason_to_break(i):
    # do something
    i += 1

Nur wenn Sie irgendwo in der Mitte der Schleife beenden müssen (oder wenn Ihre Bedingung so komplex ist, dass Ihre Schleifenanweisung weitaus weniger lesbar wird), müssen Sie sich Sorgen machen, dass sie unterbrochen wird.

Wenn Ihr potenzieller Ausgang zu Beginn der Schleife einfach ist (wie es hier zu sein scheint), ist es normalerweise besser, den Ausgang in die Schleife selbst zu codieren.

paxdiablo
quelle