2016-10-08 4 views
0

Wie unterscheidet der Bereich() in diesem Fall den Anruf?Wie funktioniert 'range()' intern?

Beispiel:

def ex(): 
    list = [1,2,3,4] 
    for val in range(len(list)): 
     print(val) 
     break 
    for val in range(len(list)): 
     print(val) 
     break 

Ausgang -

0 
0 

Kurz gesagt, meine Frage ist, warum nicht die Leistungsausbeute auf diese Weise?

0 
1 

Beim ersten Aufruf des Bereich() in dem 'ersten for-Schleife', wird der Anruf 'Bereich (len (list))', und in dem ersten Aufruf den Bereich() in der 'second for loop' ist der Aufruf 'range (len (list))', was dem zweiten Aufruf des Bereichs() in der 'first for loop' entspricht. Wie weiß Range(), ob der Aufruf von "Second for Loop" und nicht von "First for Loop" erfolgte?

+0

'range()' mit 1 arg, gibt einen Iterator zurück, der bei 0 beginnt und inkrementiert bis 'arg'. Es wird nicht wiederholt von der ersten for-Schleife aufgerufen. Sie brechen dann aus der ersten Schleife aus und starten eine neue Schleife, die einen anderen Aufruf von 'range()' ausführt, der einen Iterator zurückgibt, der bei 0 beginnt. – AChampion

+0

Warum würde es diese Ausgabe liefern? Loops beginnen nicht dort, wo der andere aufgehört hat, und Sie brechen bei der ersten Iteration. – Li357

+0

Die Antwort (auf die Frage in Ihrem Titel) hängt davon ab, welche Version von Python Sie verwenden. Python 3 'range' unterscheidet sich von Python 2's. Auch - verwenden Sie nicht "list" als Kennung. Es überschreibt einen eingebauten Namen. –

Antwort

6

Ich bin mir nicht sicher, warum Sie erwarten rangewürde erinnern, dass es zuvor aufgerufen wurde. Die Klasse behält keinen Status über vorherige Aufrufe bei. es tut einfach, was du fragst. Jeder Aufruf an range(x) gibt ein neues Objekt range zurück, das Zahlen von 0 bis x-1 bereitstellt, während Sie darüber iterieren. Jeder Anruf ist unabhängig von vorherigen Anrufen.

das Verhalten bekommen Sie beschreiben, müssen Sie das gleicheIterator für das range Objekt in jeder Schleife wieder zu verwenden.

Python 3.5.1 (default, Apr 18 2016, 11:46:32) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.29)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> l = [1,2,3,4] 
>>> r = range(len(l)) 
>>> for val in r: 
... print(val) 
... break 
... 
0 
>>> for val in r: 
... print(val) 
... break 
... 
0 
>>> i = iter(r) 
>>> for val in i: 
... print(val) 
... break 
... 
0 
>>> for val in i: 
... print(val) 
... break 
... 
1 

Sie können Bild, das so etwas wie

for x in xs: 
    do_something(x) 

kurz ist für

i = iter(xs) 
while True: 
    try: 
     x = next(i) 
    except StopIteration: 
     break 
    do_something(x) 

iter sein Argument zurück, wenn es ohnehin schon ist, in der Tat, einen Iterator, so dass jeder for Schleife gibt einen neuen Iterator am Anfang zurück, wenn Sie versuchen, ive zu iterieren r ein Nicht-Iterator iterierbar.

+0

jeder Aufruf gibt ein neues Iterator-Objekt zurück, das mit der angegebenen Sequenz (0, 1, ...) initialisiert wurde. Dieser Iterator ist das "range object", aber ich denke, der korrekte Ausdruck ist Iterator. Die for-Schleife ruft die "next" -Funktion auf, um tatsächlich über die Sequenz zu iterieren. – DanJ

+0

Das 'Bereich'-Objekt selbst ist kein Iterator; die Verwendung von "r" in beiden Schleifen erzeugt immer noch die Ausgabe in der Frage, weil jede 'for'-Schleife einen neuen Iterator aus dem' range'-Objekt holt (über 'r .__ iter__'). – chepner

+2

Ein Iterator ist etwas, das eine "__next__" -Methode bereitstellt, während ein * iterable * etwas ist, das eine "__iter__" -Methode bereitstellt. 'range' definiert' __iter__', aber nicht '__next__'. ('range .__ iter__' gibt eine Instanz von' range_iterator' zurück, was die Klasse ist, die '__next__' definiert). – chepner