Wenn Sie Python verwenden, sind Sie wahrscheinlich mit Pay attention vertraut und verwenden sie wahrscheinlich auch häufig. Es handelt sich dabei um großartige Datenstrukturen mit vielen hilfreichen Methoden, mit denen der Benutzer die Liste durch Hinzufügen, Entfernen und Sortieren von Elementen ändern kann. Es gibt jedoch einige Anwendungsfälle, in denen eine Liste zwar wie eine gute Wahl aussieht, es aber einfach nicht ist.
Dort ist das deque()
Funktion aus dem collections
Modul kann eine viel bessere Wahl sein, wenn Sie Warteschlangen und Stapel in Python implementieren müssen.
Um diesem Artikel folgen zu können, setzen wir voraus, dass Sie über einige Erfahrung mit der Python-Programmierung und der Verwendung von Pay attention und deren Methoden verfügen, da die meisten davon auf die Verwendung von collections.deque
.
Warteschlangen und Stapel
Das Wichtigste zuerst: Lassen Sie uns die Konzepte von Warteschlangen und Stapeln verstehen, bevor wir in die collections
Modul.
Warteschlangen
Eine Warteschlange ist eine Datenstruktur, die Elemente nach dem First-In-First-Out-Prinzip (FIFO) speichert. Das heißt, das erste Factor, das zur Warteschlange hinzugefügt wird, ist auch das erste Factor, das aus der Warteschlange entfernt wird.
Nehmen wir beispielsweise an, Sie fügen einer Warteschlange in Ihrem bevorzugten Musikplayer Songs hinzu. Sie haben noch nicht begonnen, Ihre Warteschlange ist additionally leer. Sie fügen dann drei Songs hinzu: song_1
, song_2
Und song_3
in dieser Reihenfolge. Jetzt sieht Ihre Warteschlange folgendermaßen aus:
queue = ('song_1', 'song_2', 'song_3')
Anschließend starten Sie die Wiedergabe des Songs in der Warteschlange. Der erste Track, der abgespielt und aus der Warteschlange entfernt wird, wird als erster hinzugefügt: song_1
– daher, als Erster rein, als erster raus. Wenn Sie dieser Regel folgen und ein paar Lieder abspielen und dann drei weitere hinzufügen, wäre dies Ihre Warteschlange:
queue = ('song_3', 'song_4', 'song_5', 'song_6')
Stapel
Ein Stapel ist eine Datenstruktur, die Elemente nach dem Final-in-First-out-Prinzip (LIFO) speichert. Das heißt, das letzte Factor, das zum Stapel hinzugefügt wird, ist das erste Factor, das vom Stapel entfernt wird.
Ein klassisches Beispiel für einen Stapel ist ein Tellerstapel. Nehmen wir an, Sie haben ein paar Freunde zum Abendessen eingeladen und benutzen fünf Teller. Nach dem Abendessen stapeln Sie diese fünf Teller in der Spüle. Sie hätten additionally diesen Stapel:
stack = ('plate_1', 'plate_2', 'plate_3', 'plate_4', 'plate_5')
Wenn Sie anfangen, das Geschirr zu spülen, beginnen Sie oben auf dem Stapel. plate_5
was bedeutet zuletzt rein, zuerst raus. Nachdem Sie additionally drei Teller gespült haben, bringt eine Freundin einen weiteren, den sie zum Nachtisch benutzt hat, und legt ihn oben auf den Stapel. Ihr Stapel sieht nun so aus:
stack = ('plate_1', 'plate_2', 'plate_6')
Das bedeutet, dass plate_6
wäre das nächste, das gewaschen wird.
Warum keine Pay attention?
Nachdem wir nun die Konzepte von Warteschlangen und Stapeln verstanden haben, könnte es so aussehen, als ob Pay attention für die Implementierung dieser Strukturen in Python völlig ausreichen würden. Schließlich wurden sie verwendet, um die Warteschlange mit Liedern und den Stapel mit Tellern darüber darzustellen, oder? Nun, das ist nicht ganz so.
Pay attention sind aus mehreren Gründen nicht die beste Datenstruktur für Warteschlangen oder Stapel in Python. Erstens sind Pay attention nicht threadsicher. Wenn additionally eine Liste von mehreren Threads gleichzeitig aufgerufen und geändert wird, kann es zu Problemen kommen und Sie erhalten wahrscheinlich inkonsistente Daten oder eine Fehlermeldung.
Pay attention sind außerdem nicht effizient, wenn Sie ein Factor von hyperlinks einfügen oder löschen müssen. Wenn Sie listing.append()
um ein Factor am rechten Ende einzufügen oder listing.pop()
um das Factor ganz rechts zu löschen, funktioniert die Liste einwandfrei. Wenn Sie jedoch versuchen, diese Vorgänge am linken Ende auszuführen, muss die Liste alle anderen Elemente nach rechts verschieben. Dies bedeutet, dass die Größe der Liste die zum Ausführen solcher Vorgänge benötigte Zeit beeinflusst, was zu einer schlechten Leistung führt.
Verwenden von collections.deque
Der deque
Objekt von collections
ist ein listenähnliches Objekt, das schnelles Anhängen und Pops von beiden Seiten unterstützt. Es unterstützt auch threadsichere, speichereffiziente Operationen und wurde speziell dafür entwickelt, bei Verwendung als Warteschlangen und Stapel effizienter als Pay attention zu sein.
Der Title „Deque“ ist die Abkürzung für „Double-Ended Queue“ und wird wie „Deck“ ausgesprochen.
Ein … Erstellen deque
Objekt
Der deque
nimmt ein Iterable als Argument an, das zu einem deque
Objekt. Wenn keines übergeben wird, ist es leer:
from collections import deque
queue = deque()
print(queue)
deque(())
Wir können aber auch jedes Iterable übergeben an deque
. Unten sehen wir, wie man Pay attention, Tupel, Mengen, Schlüssel und Werte aus Wörterbüchern in ein deque
Objekt:
songs_list = ('song_1', 'song_2', 'song_3')
songs_tuple = ('song_1', 'song_2', 'song_3')
songs_set = {'song_1', 'song_2', 'song_3'}
songs_dict = {'1': 'song_1', '2': 'song_2', '3': 'song_3'}
deque_from_list = deque(songs_list)
deque_from_tuple = deque(songs_tuple)
deque_from_set = deque(songs_set)
deque_from_dict_keys = deque(songs_dict.keys())
deque_from_dict_values = deque(songs_dict.values())
print(deque_from_list)
print(deque_from_tuple)
print(deque_from_set)
print(deque_from_dict_keys)
print(deque_from_dict_values)
deque(('song_1', 'song_2', 'song_3'))
deque(('song_1', 'song_2', 'song_3'))
deque(('song_3', 'song_1', 'song_2'))
deque(('1', '2', '3'))
deque(('song_1', 'song_2', 'song_3'))
Da wir nun unsere deque
Objekt initialisiert, können wir die Append- und Pop-Methoden verwenden, um Elemente vom rechten Ende aus einzufügen und zu löschen:
queue = deque(songs_list)
print(queue)
queue.append('song_4')
print(queue)
queue.pop()
print(queue)
deque(('song_1', 'song_2', 'song_3'))
deque(('song_1', 'song_2', 'song_3', 'song_4'))
deque(('song_1', 'song_2', 'song_3'))
Beachte das song_4
wurde ganz rechts eingefügt und dann gelöscht.
Anfügen und Löschen von hyperlinks
Einer der größten Vorteile von deque
Über einer Liste besteht die Möglichkeit, am linken Ende Elemente anzuhängen und zu löschen.
Während wir in einer Liste die insert()
Methode, mit einer deque
können wir die appendleft()
Methode. So funktioniert jede Methode:
songs_list.insert(0, 'new_song')
print(songs_list)
queue.appendleft('new_song')
print(queue)
('new_song', 'song_2', 'song_3')
deque(('new_song', 'song_1', 'song_2', 'song_3'))
Dasselbe gilt für das Löschen von Einträgen am linken Ende. In einer Liste verwenden wir die pop()
Methode mit dem Index Null als Argument, das angibt, dass das erste Factor gelöscht werden soll. In einer deque
Wir haben das popleft()
Methode zum Ausführen dieser Aufgabe:
songs_list.pop(0)
print(songs_list)
queue.popleft()
print(queue)
('song_2', 'song_3')
deque(('song_1', 'song_2', 'song_3'))
Wie bereits erwähnt, deque
Das Objekt ist für diese Vorgänge am linken Ende viel effizienter, insbesondere wenn die Größe der Warteschlange zunimmt.
Nach den Konzepten von Warteschlangen und Stapeln verwenden wir die popleft()
Methode, um das erste eingefügte Factor aus der Liste zu entfernen. Wir fügen von rechts an und entfernen von hyperlinks: als Erster rein, als erster raus.
Doch beide pop()
Und popleft()
Methoden werfen einen Fehler aus, wenn die Warteschlange leer ist. Es ist eine gute Praxis, diese Methoden in strive
Und besides
Klauseln, um Fehler zu vermeiden. Wir werden später in diesem Artikel ein Beispiel sehen.
Schließlich können wir auch die extendleft()
Methode zum Einfügen mehrerer Elemente in die Warteschlange. Diese Methode nimmt ein Iterable an. Hier ist ein Beispiel:
queue.extendleft(('new_song_1', 'new_song_2'))
print(queue)
deque(('new_song_2', 'new_song_1', 'song_1', 'song_2', 'song_3'))
Integrierte Funktionen und Iterationen in Warteschlangen
Genau wie Pay attention, Tupel und Mengen, deque
Das Objekt unterstützt auch die integrierten Funktionen von Python.
Wir können zum Beispiel verwenden len()
So überprüfen Sie die Größe einer Deque:
print(len(queue))
5
Wir können die sorted()
Funktion zum Sortieren einer Deque:
print(sorted(queue))
('new_song_1', 'new_song_2', 'song_1', 'song_2', 'song_3')
Und wir nutzen die reversed()
Funktion zum Umkehren der Reihenfolge der Elemente in einem deque
Objekt:
print(deque(reversed(queue)))
deque(('song_3', 'song_2', 'song_1', 'new_song_1', 'new_song_2'))
Der max()
Und min()
Außerdem werden folgende Funktionen unterstützt:
new_queue = deque((1, 2, 3))
print(max(new_queue))
print(min(new_queue))
3
1
Natürlich können wir die Warteschlange durchlaufen:
for tune in queue:
print(tune)
new_song_2
new_song_1
song_1
song_2
song_3
Implementieren einer Warteschlange
Lassen Sie uns nun eine vereinfachte Model einer Warteschlange in die Praxis umsetzen. Wir verwenden weiterhin das Beispiel einer Warteschlange mit Songs. Das bedeutet, dass unsere Warteschlange weiterhin neue Songs erhält, indem sie die ältesten Songs in der Reihe abspielt und sie dann entfernt. Obwohl wir eine Warteschlange implementieren, könnten wir dieselben Konzepte verwenden, um auf sehr ähnliche Weise einen Stapel zu implementieren.
Zuerst schreiben wir eine Funktion, die deque
Objekt als Warteschlange und Liste von Songs. Die Funktion wählt dann einen zufälligen Track aus und fügt ihn der Warteschlange hinzu. Die Funktion druckt auch aus, welcher Track hinzugefügt wurde, sowie die aktuelle Warteschlange. Dieser Vorgang wird unendlich fortgesetzt.
def add_song(queue, songs):
whereas True:
index = randint(0, len(songs))
tune = songs(index)
queue.append(tune)
print(f'Track Added: {tune}, Queue: {queue}')
sleep(randint(0, 5))
Wir brauchen jetzt eine Funktion, um die Songs zu entfernen, während sie abgespielt werden. Diese Funktion spielt eigentlich keinen Track ab, da das Ziel nur darin besteht, eine Darstellung der Warteschlangenfunktion in Python zu erstellen. Stattdessen nimmt diese Funktion eine Warteschlange auf, löscht das äußerste linke Factor und druckt das gelöschte Factor und die aktuelle Warteschlange aus. Wenn die Warteschlange leer ist, druckt die Funktion dies aus.
def play_song(queue):
whereas True:
strive:
tune = queue.popleft()
print(f'Track Performed: {tune}, Queue: {queue}')
besides IndexError:
print('Queue is empty.')
sleep(randint(0, 5))
Als nächstes erstellen wir eine Liste von Songs und instantiieren einen deque
Objekt. Schließlich verwenden wir Pythons threading
Modul, um beide Funktionen gleichzeitig auszuführen. Dies ist der endgültige Code:
from threading import Thread
from collections import deque
from time import sleep
from random import randint
songs = (f'song_{i+1}' for i in vary(100))
def add_song(queue, songs):
whereas True:
index = randint(0, len(songs))
tune = songs(index)
queue.append(tune)
print(f'Track Added: {tune}, Queue: {queue}')
sleep(randint(0, 5))
def play_song(queue):
whereas True:
strive:
tune = queue.popleft()
print(f'Track Performed: {tune}, Queue: {queue}')
besides IndexError:
print('Queue is empty.')
sleep(randint(0, 5))
queue = deque()
Thread(goal=add_song, args=(queue, songs)).begin()
Thread(goal=play_song, args=(queue,)).begin()
Wenn wir den obigen Code ausführen, erhalten wir eine Ausgabe wie die folgende:
Track Added: song_60, Queue: deque(('song_60'))
Track Performed: song_60, Queue: deque(())
Queue is empty.
Queue is empty.
Track Added: song_13, Queue: deque(('song_13'))
Track Performed: song_13, Queue: deque(())
Queue is empty.
Track Added: song_59, Queue: deque(('song_59'))
Track Added: song_46, Queue: deque(('song_59', 'song_46'))
Track Added: song_48, Queue: deque(('song_59', 'song_46', 'song_48'))
Track Performed: song_59, Queue: deque(('song_46', 'song_48'))
Track Added: song_3, Queue: deque(('song_46', 'song_48', 'song_3'))
Track Performed: song_46, Queue: deque(('song_48', 'song_3'))
Track Added: song_98, Queue: deque(('song_48', 'song_3', 'song_98'))
Track Performed: song_48, Queue: deque(('song_3', 'song_98'))
Beachten Sie, dass der Code Songs am rechten Ende der Warteschlange hinzufügt und sie am linken Ende entfernt, wobei die vom Benutzer definierte Reihenfolge der Songs beachtet wird. Da deque
unterstützt Multithreading, wir haben keine Probleme, wenn zwei Funktionen gleichzeitig auf dasselbe Objekt zugreifen und es ändern.
Abschluss
In diesem Artikel haben wir beschrieben, wie die deque
Objekt von collections
kann eine gute Wahl für die Implementierung von Warteschlangen und Stapeln in Python sein. Wir haben auch Folgendes behandelt:
-
Die Konzepte von Warteschlangen und Stapeln
-
Warum Pay attention in diesem Fall nicht die beste Wahl sind
-
So verwenden Sie die
deque
Objekt -
Implementierung einer vereinfachten Model einer in der Produktion funktionierenden Warteschlange