Heim  >  Artikel  >  Datenbank  >  Was ist range()? Warum nicht Iteratoren produzieren?

Was ist range()? Warum nicht Iteratoren produzieren?

不言
不言nach vorne
2019-01-07 10:30:513910Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Frage, was „range()“ ist. Warum nicht Iteratoren produzieren? Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird Ihnen hilfreich sein.

Iterator ist eines der am häufigsten verwendeten (eines) der 23 Entwurfsmuster. Wir verwenden es oft, sind uns aber nicht unbedingt seiner Existenz bewusst. In meiner Serie über Iteratoren (Link am Ende des Artikels) habe ich mindestens 23 Möglichkeiten zum Generieren von Iteratoren erwähnt. Einige Methoden werden speziell zum Generieren von Iteratoren verwendet, während andere Iteratoren „heimlich“ verwenden, um andere Probleme zu lösen.

Bevor das System etwas über Iteratoren lernte, dachte ich immer, dass die Methode range() auch zum Generieren von Iteratoren verwendet wird, aber jetzt stellte ich plötzlich fest, dass sie nur iterierbare Objekte generiert, keine Iteratoren! (PS: range() in Python2 generiert eine Liste, dieser Artikel basiert auf Python3 und generiert ein iterierbares Objekt)

Ich habe also diese Frage: Warum generiert range() keinen Iterator? Bei der Suche nach Antworten stellte ich fest, dass ich einige Missverständnisse über den Bereichstyp hatte. Daher vermittelt Ihnen dieser Artikel ein umfassendes Verständnis der Reichweite und ich freue mich darauf, gemeinsam mit Ihnen zu lernen und Fortschritte zu erzielen.

1. Was ist range()?

Seine Syntax: range(start, stop [,step]); Stop; Schritt ist die Schrittgröße, der Standardwert ist 1 und kann nicht 0 sein. Die Methode range() generiert einen Bereich von Ganzzahlen, der links geschlossen und rechts offen ist.

>>> a = range(5)  # 即 range(0,5)
>>> a
range(0, 5)
>>> len(a)
5
>>> for x in a:
>>>     print(x,end=" ")
0 1 2 3 4

Bei der Funktion range() sind mehrere Punkte zu beachten: (1) Sie stellt ein links-geschlossenes und rechts-offenes Intervall dar. (2) Der empfangene Parameter muss eine ganze Zahl sein eine negative Zahl, kann jedoch keine Gleitkommazahl oder ein anderer Typ sein. (3) Es handelt sich um einen unveränderlichen Sequenztyp, der Operationen wie das Beurteilen von Elementen, das Finden von Elementen, das Schneiden usw. ausführen kann, aber keine Elemente ändern kann. (4) Dies ist der Fall ein iterierbares Objekt, aber kein Iterator.

# (1)左闭右开
>>> for i in range(3, 6):
>>>     print(i,end=" ")
3 4 5

# (2)参数类型
>>> for i in range(-8, -2, 2):
>>>     print(i,end=" ")
-8 -6 -4
>>> range(2.2)
----------------------------
TypeError    Traceback (most recent call last)
...
TypeError: 'float' object cannot be interpreted as an integer

# (3)序列操作
>>> b = range(1,10)
>>> b[0]
1
>>> b[:-3]
range(1, 7)
>>> b[0] = 2
TypeError  Traceback (most recent call last)
...
TypeError: 'range' object does not support item assignment

# (4)不是迭代器
>>> hasattr(range(3),'__iter__')
True
>>> hasattr(range(3),'__next__')
False
>>> hasattr(iter(range(3)),'__next__')
True

2. Warum erzeugt range() keinen Iterator?

Es gibt viele integrierte Methoden zum Abrufen von Iteratoren, wie z. B. zip(), enumerate(), map(), filter() und reversed() usw., aber wie range() Nur die Methode eines iterierbaren Objekts ist eindeutig (falls es Gegenbeispiele gibt, teilen Sie uns dies bitte mit). Hier habe ich ein Missverständnis meines Wissens.

Während des For-Schleifendurchlaufs ist die Leistung iterierbarer Objekte und Iteratoren gleich, das heißt, sie werden beide träge ausgewertet, und es gibt keinen Unterschied in der räumlichen und zeitlichen Komplexität. Ich habe den Unterschied zwischen den beiden einmal als „das Gleiche, aber zwei verschiedene Dinge“ zusammengefasst: Das Gleiche ist, dass beide träge iteriert werden können, aber der Unterschied besteht darin, dass das iterierbare Objekt die Selbstdurchquerung (d. h. die next()-Methode) nicht unterstützt ), und der Iterator selbst unterstützt kein Slicing (d. h. die __getitem__()-Methode).

Trotz dieser Unterschiede ist es schwer zu entscheiden, welches besser ist. Die Feinheit ist nun: Warum sind Iteratoren für alle fünf integrierten Methoden konzipiert, die Methode range() jedoch als iterierbares Objekt? Wäre es nicht besser, sie alle zu vereinen?

Tatsächlich hat Python aus Gründen der Standardisierung viele dieser Dinge getan. Beispielsweise gibt es in Python2 zwei Methoden, „range()“ und „xrange()“, aber Python3 hat eine davon eliminiert verwendete auch die Methode „Li Dai Tao Jian“. Warum nicht formeller vorgehen und range() einen Iterator generieren lassen?

Ich habe keine offizielle Erklärung zu diesem Thema gefunden. Das Folgende ist eine rein persönliche Meinung.

zip() und andere Methoden müssen die Parameter bestimmter iterierbarer Objekte empfangen, was ein Prozess ihrer erneuten Verarbeitung ist. Daher hoffen sie auch, bestimmte Ergebnisse sofort zu erzielen, also entwerfen Python-Entwickler Das Ergebnis ist ein Iterator . Dies hat auch den Vorteil, dass bei einer Änderung des als Parameter verwendeten iterierbaren Objekts der als Ergebnis verwendete Iterator nicht falsch verwendet wird, da er verbrauchbar ist.

Die Methode range() ist anders. Der empfangene Parameter ist kein iterierbarer Prozess, daher ist er als iterierbares Objekt konzipiert, das direkt oder für andere Wiederverarbeitungszwecke verwendet werden kann . Methoden wie zip() können beispielsweise Bereichstypparameter akzeptieren.

>>> for i in zip(range(1,6,2), range(2,7,2)):
>>>    print(i, end="")
(1, 2)(3, 4)(5, 6)

Mit anderen Worten, die range()-Methode ist ein Primärproduzent, und die von ihr produzierten Rohstoffe haben großartige Verwendungsmöglichkeiten. Es wäre zweifellos überflüssig, sie frühzeitig in einen Iterator umzuwandeln.

Halten Sie diese Interpretation für sinnvoll? Besprechen Sie dieses Thema gerne mit mir.

3. Was ist der Bereichstyp?

Das Obige ist meine Antwort auf „Warum range() keinen Iterator generiert“. Dieser Idee folgend, habe ich das von ihm erzeugte Entfernungsobjekt untersucht und bei der Recherche festgestellt, dass dieses Entfernungsobjekt nicht einfach ist.

Das erste Merkwürdige ist, dass es sich um eine unveränderliche Sequenz handelt! Das ist mir nie aufgefallen. Obwohl ich nie darüber nachgedacht habe, den Wert von range() zu ändern, hat mich diese nicht veränderbare Funktion dennoch überrascht.

Ein Blick in die Dokumentation zeigt, dass die offizielle Aufteilung wie folgt lautet: Es gibt drei grundlegende Sequenztypen: Liste, Tupel und Bereichsobjekt. (Es gibt drei grundlegende Sequenztypen: Listen, Tupel und Bereichsobjekte.)

这我倒一直没注意,原来 range 类型居然跟列表和元组是一样地位的基础序列!我一直记挂着字符串是不可变的序列类型,不曾想,这里还有一位不可变的序列类型呢。

那 range 序列跟其它序列类型有什么差异呢?

普通序列都支持的操作有 12 种,在《你真的知道Python的字符串是什么吗?》这篇文章里提到过。range 序列只支持其中的 10 种,不支持进行加法拼接与乘法重复。

>>> range(2) + range(3)
-----------------------------------------
TypeError  Traceback (most recent call last)
...
TypeError: unsupported operand type(s) for +: 'range' and 'range'

>>> range(2)*2
-----------------------------------------
TypeError  Traceback (most recent call last)
...
TypeError: unsupported operand type(s) for *: 'range' and 'int'

那么问题来了:同样是不可变序列,为什么字符串和元组就支持上述两种操作,而偏偏 range 序列不支持呢?虽然不能直接修改不可变序列,但我们可以将它们拷贝到新的序列上进行操作啊,为何 range 对象连这都不支持呢?

且看官方文档的解释:

...due to the fact that range objects can only represent sequences that follow a strict pattern and repetition and concatenation will usually violate that pattern.

原因是 range 对象仅仅表示一个遵循着严格模式的序列,而重复与拼接通常会破坏这种模式...

问题的关键就在于 range 序列的 pattern,仔细想想,其实它表示的就是一个等差数列啊(喵,高中数学知识没忘...),拼接两个等差数列,或者重复拼接一个等差数列,想想确实不妥,这就是为啥 range 类型不支持这两个操作的原因了。由此推论,其它修改动作也会破坏等差数列结构,所以统统不给修改就是了。

4、小结

回顾全文,我得到了两个偏冷门的结论:range 是可迭代对象而不是迭代器;range 对象是不可变的等差序列。

若单纯看结论的话,你也许没有感触,或许还会说这没啥了不得啊。但如果我追问,为什么 range 不是迭代器呢,为什么 range 是不可变序列呢?对这俩问题,你是否还能答出个自圆其说的设计思想呢?(PS:我决定了,若有机会面试别人,我必要问这两个问题的嘿~)

由于 range 对象这细微而有意思的特性,我觉得这篇文章写得值了。本文是作为迭代器系列文章的一篇来写的,所以对于迭代器的基础知识介绍不多,欢迎查看之前的文章。另外,还有一种特殊的迭代器也值得单独成文,那就是生成器了,敬请期待后续推文哦~

Das obige ist der detaillierte Inhalt vonWas ist range()? Warum nicht Iteratoren produzieren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen