One place for hosting & domains

      verwenden

      Verwenden der Python-Filterfunktion


      Einführung

      Die in Python integrierte filter()-Funktion kann dazu dienen, aus einem vorhandenen iterable (wie einer Liste oder einem Wörterbuch) einen neuen iterator zu erstellen, der Elemente mithilfe einer von uns bereitgestellten Funktion effizient filtern kann. Ein iterable ist ein Python-Objekt, bei dem „iterated over“ möglich ist, d. h. Elemente werden in einer Reihenfolge zurückgegeben, die wir in einer for-Schleife verwenden können.

      Die grundlegende Syntax für die Funktion filter() lautet:

      filter(function, iterable)
      

      Dadurch wird ein Filterobjekt zurückgegeben, das ein iterable ist. Wir können eine Funktion wie list() verwenden, um eine Liste aller in einem Filterobjekt zurückgegebenen Elemente zu erstellen.

      Die Funktion filter() bietet eine Möglichkeit, Werte zu filtern, die oft effizienter ist als eine Listen-Abstraktion, insbesondere wenn wir mit größeren Datensätzen arbeiten. Beispielsweise erstellt eine Listen-Abstraktion eine neue Liste, was die Laufzeit dieser Verarbeitung erhöht. So verfügen wir, nachdem unsere Listen-Abstraktion ihren Ausdruck abgeschlossen hat, über zwei Listen im Arbeitsspeicher. Allerdings wird filter() ein einfaches Objekt erstellen, das einen Verweis auf die Originalliste, die bereitgestellte Funktion und einen Index enthält, wo in der Originalliste gesucht werden soll. Dafür wird weniger Arbeitsspeicher benötigt.

      In diesem Tutorial werden wir uns vier verschiedene Methoden zur Verwendung von filter() ansehen: mit zwei verschiedenen iterable-Strukturen, mit einer lambda-Funktion und ohne definierte Funktion.

      Verwenden von filter() mit einer Funktion

      Das erste Argument für filter() ist eine Funktion, mit der wir entscheiden, ob die einzelnen Elemente enthalten sein oder herausgefiltert werden sollen. Die Funktion wird für jedes Element im iterable, das als zweites Argument übergeben wird, einmal aufgerufen, und bei jeder Rückgabe von False wird der Wert gelöscht. Da dieses Argument eine Funktion ist, können wir entweder eine normale Funktion übergeben oder lambda-Funktionen nutzen, insbesondere wenn der Ausdruck weniger komplex ist.

      Im Folgenden wird die Syntax einer lambda-Funktion mit filter() dargestellt:

      filter(lambda item: item[] expression, iterable)
      

      Mit einer Liste wie dieser können wir eine lambda-Funktion mit einem Ausdruck integrieren, gegen den wir die einzelnen Elemente aus der Liste bewerten möchten:

      creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']
      

      Um die Liste zu filtern und die Namen unserer Aquariumbewohner zu finden, die mit einem Vokal beginnen, können wir die folgende lambda-Funktion ausführen:

      print(list(filter(lambda x: x[0].lower() in 'aeiou', creature_names)))
      

      Hier deklarieren wir einen Punkt in unserer Liste als x. Dann legen wir unseren Ausdruck so fest, dass er auf das erste Zeichen der jeweiligen Zeichenfolge (oder Zeichen „zero“) zugreift, also x[0]. Durch Kleinschreibung aller Namen wird sichergestellt, dass Buchstaben mit der Zeichenfolge in unserem Ausdruck (aeiou) abgeglichen werden.

      Abschließend übergeben wir das iterable creature_names. Wie im vorherigen Abschnitt wenden wir list() auf das Ergebnis an, um eine Liste aus den iterator filter()-Ergebnissen zu erstellen.

      Die Ausgabe wird wie folgt aussehen:

      Output

      ['Ashley', 'Olly']

      Das gleiche Ergebnis kann mit einer selbst definierten Funktion erzielt werden:

      creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']
      
      def names_vowels(x):
        return x[0].lower() in 'aeiou'
      
      filtered_names = filter(names_vowels, creature_names)
      
      print(list(filtered_names))
      

      Unsere Funktion names_vowels definiert den Ausdruck, den wir implementieren werden, um creature_names zu filtern.

      Die Ausgabe würde erneut wie folgt aussehen:

      Output

      ['Ashley', 'Olly']

      Im Allgemeinen erzielen lambda-Funktionen mit filter() das gleiche Ergebnis, wie wenn wir eine reguläre Funktion verwenden würden. Die Notwendigkeit zur Definition einer regulären Funktion wächst mit der Komplexität der Ausdrücke zum Filtern unserer Daten. Dadurch lässt sich in unserem Code wahrscheinlich auch eine bessere Lesbarkeit erzielen.

      Verwenden von None mit filter()

      Wir können None als erstes Argument an filter() übergeben, damit der zurückgegebene iterator alle Werte ausgibt, die Python als „falsy“ erachtet. Im Allgemeinen betrachtet Python alles mit einer Länge von 0 (wie eine leere Liste oder eine leere Zeichenfolge) und alles, was 0 numerisch entspricht, als „false“, daher die Verwendung des Begriffs „falsy“.

      Im folgenden Fall möchten wir unsere Liste so filtern, dass nur die Tanknummern unseres Aquariums angezeigt werden:

      aquarium_tanks = [11, False, 18, 21, "", 12, 34, 0, [], {}]
      

      In diesem Code haben wir eine Liste, die Integer, leere Sequenzen und einen booleschen Wert enthält.

      filtered_tanks = filter(None, aquarium_tanks)
      

      Wir verwenden die Funktion filter() mit None und übergeben die Liste aquarium_tanks als unser iterable. Da wir None als erstes Argument übergeben haben, prüfen wir, ob die Elemente in unserer Liste als false angesehen werden.

      print(list(filtered_tanks))
      

      Dann schließen wir filtered_tanks in eine list()-Funktion ein, damit sie beim Drucken eine Liste für filtered_tanks zurückgibt.

      Hier sehen wir, dass die Ausgabe nur die Integerwerte enthält. Alle Elemente, die zu False ausgewertet wurden oder der Länge 0 entsprechen, wurden durch filter() entfernt:

      Output

      [11, 25, 18, 21, 12, 34]

      Anmerkung: Wenn wir list() nicht verwenden und filtered_tanks drucken, erhalten wir ein Filterobjekt, das etwa so aussieht: <Filter object at 0x7fafd5903240>. Das Filterobjekt ist ein iterable, sodass wir ein loop over mit for vornehmen können; alternativ können wir list() verwenden, um es in eine Liste umzuwandeln. Dies tun wir hier, da es eine gute Möglichkeit ist, die Ergebnisse zu prüfen.

      Bei None haben wir filter() verwendet, um Elemente aus unserer Liste schnell zu entfernen, die als false betrachtet wurden.

      Verwenden von filter() mit einer Liste von Wörterbüchern

      Wenn wir eine komplexere Datenstruktur aufweisen, können wir filter() dennoch verwenden, um die einzelnen Elemente zu bewerten. Wenn wir beispielsweise über eine Liste von Wörterbüchern verfügen, wollen wir nicht nur über jedes einzelne Element in der Liste – einem der Wörterbücher – iterieren, sondern wollen ggf. auch über jedes key:value-Paar in einem Wörterbuch iterieren, um alle Daten auszuwerten.

      Als Beispiel gehen wir davon aus, dass wir eine Liste jedes einzelnen Tiers in unserem Aquarium sowie verschiedene Details zu ihnen haben:

      aquarium_creatures = [
        {"name": "sammy", "species": "shark", "tank number": "11", "type": "fish"},
        {"name": "ashley", "species": "crab", "tank number": "25", "type": "shellfish"},
        {"name": "jo", "species": "guppy", "tank number": "18", "type": "fish"},
        {"name": "jackie", "species": "lobster", "tank number": "21", "type": "shellfish"},
        {"name": "charlie", "species": "clownfish", "tank number": "12", "type": "fish"},
        {"name": "olly", "species": "green turtle", "tank number": "34", "type": "turtle"}
      ]
      

      Wir möchten diese Daten mit einer Suchzeichenfolge filtern, die wir der Funktion übergeben. Damit filter() auf jedes Wörterbuch und jedes Element in den Wörterbüchern zugreift, richten wir eine geschachtelte Funktion ein, die wie folgt aussieht:

      def filter_set(aquarium_creatures, search_string):
          def iterator_func(x):
              for v in x.values():
                  if search_string in v:
                      return True
              return False
          return filter(iterator_func, aquarium_creatures)
      

      Wir definieren eine filter_set()-Funktion, die aquarium_creatures und search_string als Parameter verwendet. In filter_set() übergeben wir unsere iterator_func() als Funktion an filter(). Die Funktion filter_set() gibt den iterator zurück, der aus filter() resultiert.

      Die iterator_func() nimmt x als Argument, was ein Element in unserer Liste (d. h. einem einzelnen Wörterbuch) darstellt.

      Als Nächstes greift die for-Schleife auf die Werte in den einzelnen key:value-Paaren in unseren Wörterbüchern zu und nutzt dann eine bedingte Anweisung, um zu prüfen, ob die search_string in v ist, was einen Wert darstellt.

      Wie in unseren vorherigen Beispielen: Wenn der Ausdruck zu True auswertet, fügt die Funktion das Element dem Filterobjekt hinzu. Dieses wird zurückgegeben, sobald die Funktion filter_set() abgeschlossen ist. Wir positionieren return False außerhalb unserer Schleife, damit jedes Element in jedem Wörterbuch geprüft wird, anstatt nach der Überprüfung des ersten Wörterbuchs zurückzukehren.

      Wir rufen filter_set() mit unserer Liste der Wörterbücher und der Suchzeichenfolge auf, für die wir Übereinstimmungen finden möchten:

      filtered_records = filter_set(aquarium_creatures, "2")    
      

      Nach Abschluss der Funktion ist unser Filterobjekt in der Variable filtered_records gespeichert, die wir in eine Liste verwandeln und drucken:

      print(list(filtered_records))      
      

      Wir sehen die folgende Ausgabe aus diesem Programm:

      Output

      [{'name': 'ashley', 'species': 'crab', 'tank number': '25', 'type': 'shellfish'}, {'name': 'jackie', 'species': 'lobster', 'tank number': '21', 'type': 'shellfish'}, {'name': 'charlie', 'species': 'clownfish', 'tank number': '12', 'type': 'fish'}]

      Wir haben die Liste der Wörterbücher mit der Suchzeichenfolge 2 gefiltert. Wir können sehen, dass die drei Wörterbücher zurückgegeben wurden, die eine Tanknummer mit 2 enthielten. Mit unserer eigenen geschachtelten Funktion können wir auf jedes einzelne Element zugreifen und effizient mit der Suchzeichenfolge abgleichen.

      Zusammenfassung

      In diesem Tutorial haben wir die verschiedenen Möglichkeiten zur Verwendung der Funktion filter() in Python kennengelernt. Jetzt können Sie filter() mit Ihrer eigenen Funktion, einer lambda-Funktion oder mit None verwenden, um in Datenstrukturen unterschiedlicher Komplexität nach Elementen zu filtern.

      Zwar haben wir in diesem Tutorial die Ergebnisse von filter() sofort im Listenformat gedruckt, doch ist es wahrscheinlich, dass wir das zurückgegebene filter()-Objekt in unseren Programmen verwenden und die Daten weiter bearbeiten werden.

      Wenn Sie mehr über Python erfahren möchten, lesen Sie unsere Reihe Codieren in Python 3 und unsere Python Themenseite.



      Source link

      Installieren und Verwenden von Docker Compose unter Ubuntu 20.04


      Einführung

      Docker vereinfacht die Verwaltung von Anwendungsprozessen in Containern. Obwohl Container in gewisser Hinsicht virtuellen Rechnern ähneln, sind sie leichter und ressourcenschonender. Dies ermöglicht Entwicklern, eine Anwendungsumgebung in mehrere isolierte Dienste zu unterteilen.

      Bei Anwendungen, die von mehreren Diensten abhängig sind, kann die Organisation aller Container zum gemeinsamen Starten, Kommunizieren und Herunterfahren schnell unhandlich werden. Docker Compose ist ein Tool, mit dem Sie Anwendungsumgebungen mit mehreren Containern basierend auf in einer YAML-Datei festgelegten Definitionen ausführen können. Er verwendet Dienst-Definitionen zum Aufbau voll anpassbarer Umgebungen mit mehreren Containern, die Netzwerke und Datenvolumes teilen können.

      In diesem Leitfaden zeigen wir Ihnen, wie Sie Docker Compose auf einem Ubuntu 20.04-Server installieren und wie Sie mit der Verwendung dieses Tools beginnen können.

      Voraussetzungen

      Um diese Anleitung mitzuverfolgen, benötigen Sie:

      Schritt 1 – Installieren von Docker Compose

      Um sicherzustellen, dass wir die aktuellste stabile Version von Docker Compose erhalten, werden wir diese Software von ihrem offiziellen Github-Repository herunterladen.

      Bestätigen Sie zunächst die auf ihrer Seite verfügbare neueste Version. Zum Zeitpunkt des Schreibens dieses Artikels ist die aktuellste stabile Version 1.26.0.

      Mit dem folgenden Befehl wird die Version 1.26.0 herunterladen und die ausführbare Datei unter /usr/local/bin/docker-compose gespeichert, wodurch diese Software global als docker-compose zugänglich wird:

      • sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

      Legen Sie als Nächstes die richtigen Berechtigungen fest, damit der Befehl docker-compose ausführbar ist:

      • sudo chmod +x /usr/local/bin/docker-compose

      Um zu überprüfen, ob die Installation erfolgreich war, können Sie Folgendes ausführen:

      Sie sehen eine Ausgabe, die dieser ähnelt:

      Output

      docker-compose version 1.26.0, build 8a1c60f6

      Docker Compose ist nun erfolgreich auf Ihrem System installiert. Im nächsten Abschnitt sehen wir uns an, wie Sie eine docker-compose.yml-Datei einrichten und mit diesem Tool eine containerisierte Umgebung zum Laufen bringen.

      Schritt 2 — Einrichten einer docker-compose.yml-Datei

      Um zu zeigen, wie eine docker-compose.yml-Datei eingerichtet und mit Docker Compose gearbeitet wird, erstellen wir unter Verwendung des offiziellen Nginx-Images vom Docker Hub, der öffentlichen Docker-Registry, eine Webserverumgebung Diese containerisierte Umgebung wird eine einzelne statische HTML-Datei bereitstellen.

      Beginnen Sie mit der Erstellung eines neuen Verzeichnisses in Ihrem Home-Ordner und verschieben Sie dieses dann zu:

      • mkdir ~/compose-demo
      • cd ~/compose-demo

      Richten Sie in diesem Verzeichnis einen Anwendungsordner ein, der als Dokumentenstamm für Ihre Nginx-Umgebung dient:

      Erstellen Sie mit Ihrem bevorzugten Texteditor eine neue index.html-Datei innerhalb des Ordners app:

      Geben Sie den folgenden Inhalt in diese Datei ein:

      ~/compose-demo/app/index.html

      <!doctype html>
      <html lang="en">
      <head>
          <meta charset="utf-8">
          <title>Docker Compose Demo</title>
          <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kognise/water.css@latest/dist/dark.min.css">
      </head>
      <body>
      
          <h1>This is a Docker Compose Demo Page.</h1>
          <p>This content is being served by an Nginx container.</p>
      
      </body>
      </html>
      

      Speichern und schließen Sie die Datei, wenn Sie fertig sind. Wenn Sie nano verwenden, können Sie STRG+X drücken, dann Y eingeben und zur Bestätigung ENTER drücken.

      Erstellen Sie als Nächstes die Datei docker-compose.yml:

      Geben Sie den folgenden Inhalt in Ihre Datei docker-compose.yml ein:

      docker-compose.yml

      version: '3.7'
      services:
        web:
          image: nginx:alpine
          ports:
            - "8000:80"
          volumes:
            - ./app:/usr/share/nginx/html
      

      Die Datei docker-compose.yml beginnt typischerweise mit der version-Definition. Dadurch wird Docker Compose mitgeteilt, welche Konfigurationsversion wir verwenden.

      Dann haben wir den services-Block, in dem wir die Dienste einrichten, die Teil dieser Umgebung sind. In unserem Fall haben wir einen einzigen Dienst namens web. Dieser Dienst verwendet das Image nginx:alpine und richtet mit der Anweisung ports eine Portumleitung ein. Alle Anfragen auf Port 8000 des Host-Rechners (das System, von dem aus Docker Compose ausgeführt wird) werden auf den Web-Container auf Port 80 umgeleitet, wo Nginx ausgeführt wird.

      Die Anweisung volumes erstellt ein gemeinsames Volumen zwischen dem Host-Rechner und dem Container. Dadurch wird der lokale Ordner app mit dem Container geteilt und das Volumen befindet sich unter /usr/share/nginx/html innerhalb des Containers, der dann den Standard-Dokumentenstamm für Nginx überschreibt.

      Speichern und schließen Sie die Datei.

      Wir haben eine Demo-Seite und eine Datei docker-compose.yml eingerichtet, um eine containerisierte Webserverumgebung zu erstellen, die sie bedienen wird. Im nächsten Schritt stellen wir diese Umgebung mit Docker Compose bereit.

      Schritt 3 — Ausführen von Docker Compose

      Mit der docker-compose.yml-Datei können wir nun Docker Compose ausführen, um unserer Umgebung aufzurufen. Der folgende Befehl lädt die erforderlichen Docker-Images herunter, erstellt einen Container für den web-Dienst und führt die containerisierte Umgebung im Hintergrundmodus aus:

      Docker Compose sucht zunächst nach dem definierten Image auf Ihrem lokalen System, und wenn es das Image nicht lokalisieren kann, wird es das Image vom Docker Hub herunterladen. Die Ausgabe sieht dann so aus:

      Output

      Creating network "compose-demo_default" with the default driver Pulling web (nginx:alpine)... alpine: Pulling from library/nginx cbdbe7a5bc2a: Pull complete 10c113fb0c77: Pull complete 9ba64393807b: Pull complete c829a9c40ab2: Pull complete 61d685417b2f: Pull complete Digest: sha256:57254039c6313fe8c53f1acbf15657ec9616a813397b74b063e32443427c5502 Status: Downloaded newer image for nginx:alpine Creating compose-demo_web_1 ... done

      Ihre Umgebung ist nun aktiviert und wird im Hintergrund ausgeführt. Um zu überprüfen, ob der Container aktiv ist, können Sie Folgendes ausführen:

      Dieser Befehl zeigt Ihnen Informationen über die ausgeführten Container und ihren Zustand sowie alle derzeit bestehenden Portumleitungen an:

      Output

      Name Command State Ports ---------------------------------------------------------------------------------- compose-demo_web_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8000->80/tcp

      Sie können nun auf die Demo-Anwendung zugreifen, indem Sie Ihren Browser entweder auf localhost:8000 verweisen, wenn Sie diese Demo auf Ihrem lokalen Rechner ausführen, oder auf your_server_domain_or_IP:8000, wenn Sie diese Demo auf einem Remote-Server ausführen.

      Sie sehen in etwa folgende Seite:

      Docker Compose Demo-Seite

      Da das gemeinsame Volumen, das Sie in der Datei docker-compose.yml eingerichtet haben, Ihre app-Orderndateien mit dem Dokumentenstamm des Containers synchronisiert hält. Wenn Sie Änderungen an der Datei index.html vornehmen, werden diese automatisch vom Container übernommen und somit in Ihrem Browser angezeigt, wenn Sie die Seite neu laden.

      Im nächsten Schritt sehen Sie, wie Ihre containerisierte Umgebung mit den Docker Compose-Befehlen verwaltet wird.

      Schritt 4 — Kennenlernen der Befehle von Docker Compose

      Sie haben gesehen, wie Sie eine docker-compose.yml-Datei einrichten und Ihre Umgebung mit docker-compose aufrufen. Nun sehen Sie, wie Sie die Docker Compose-Befehle verwenden, um Ihre containerisierte Umgebung zu verwalten und mit ihr zu interagieren.

      Um die von Ihrem Nginx-Container erzeugten Protokolle zu überprüfen, können Sie den Befehl logs verwenden:

      Sie sehen eine Ausgabe, die dieser ähnelt:

      Output

      Attaching to compose-demo_web_1 web_1 | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration web_1 | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ web_1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh web_1 | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf web_1 | 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf web_1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh web_1 | /docker-entrypoint.sh: Configuration complete; ready for start up web_1 | 172.22.0.1 - - [02/Jun/2020:10:47:13 +0000] "GET / HTTP/1.1" 200 353 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" "-"

      Wenn Sie die Ausführung der Umgebung unterbrechen möchten, ohne den aktuellen Zustand Ihrer Container zu ändern, können Sie Folgendes verwenden:

      Output

      Pausing compose-demo_web_1 ... done

      Um die Ausführung nach einer Unterbrechung fortzusetzen:

      Output

      Unpausing compose-demo_web_1 ... done

      Der Befehl stop beendet die Ausführung des Containers, zerstört jedoch keine Daten, die mit Ihren Containern verknüpft sind:

      Output

      Stopping compose-demo_web_1 ... done

      Wenn Sie die mit dieser containerisierten Umgebung verknüpften Container, Netzwerke und Volumen entfernen möchten, verwenden Sie den Befehl down:

      Output

      Removing compose-demo_web_1 ... done Removing network compose-demo_default

      Beachten Sie, dass dadurch nicht das Basis-Image entfernt wird, das von Docker Compose zum Hochfahren Ihrer Umgebung verwendet wird (in unserem Fall nginx:alpine). Auf diese Weise wird der Prozess jedes Mal, wenn Sie Ihre Umgebung mit einem docker-compose up wieder hochfahren, viel schneller sein, da sich das Image bereits auf Ihrem System befindet.

      Falls Sie auch das Basis-Image von Ihrem System entfernen möchten, können Sie Folgendes verwenden:

      • docker image rm nginx:alpine

      Output

      Untagged: nginx:alpine Untagged: nginx@sha256:b89a6ccbda39576ad23fd079978c967cecc6b170db6e7ff8a769bf2259a71912 Deleted: sha256:7d0cdcc60a96a5124763fddf5d534d058ad7d0d8d4c3b8be2aefedf4267d0270 Deleted: sha256:05a0eaca15d731e0029a7604ef54f0dda3b736d4e987e6ac87b91ac7aac03ab1 Deleted: sha256:c6bbc4bdac396583641cb44cd35126b2c195be8fe1ac5e6c577c14752bbe9157 Deleted: sha256:35789b1e1a362b0da8392ca7d5759ef08b9a6b7141cc1521570f984dc7905eb6 Deleted: sha256:a3efaa65ec344c882fe5d543a392a54c4ceacd1efd91662d06964211b1be4c08 Deleted: sha256:3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a

      Anmerkung: Eine ausführliche Referenz zu den Docker-Befehlen finden Sie in unserem Leitfaden zum Installieren und Verwenden von Docker.

      Zusammenfassung

      In diesem Leitfaden haben wir gesehen, wie wir Docker Compose installieren und eine containerisierte Umgebung basierend auf einem Nginx Webserver-Image einrichten. Wir haben auch gesehen, wie diese Umgebung mit den Compose-Befehlen verwaltet wird.

      Eine vollständige Referenz aller verfügbaren docker-compose Befehle finden Sie in der offiziellen Dokumentation.



      Source link

      Verwenden des collections-Moduls in Python 3


      Der Autor hat den COVID-19 Relief Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      Einführung

      Python 3 verfügt über eine Reihe von integrierten Datenstrukturen, einschließlich Tupel, Wörterbücher und Listen. Datenstrukturen bieten uns eine Möglichkeit, Daten zu organisieren und zu speichern. Das collections-Modul hilft uns, Datenstrukturen effizient zu füllen und zu manipulieren.

      In diesem Tutorial gehen wir drei Klassen im collections-Modul durch, um Ihnen die Arbeit mit Tupeln, Wörterbüchern und Listen zu erleichtern. Wir verwenden namedtuples, um Tupel mit benannten Feldern zu erstellen, defaultdict, um Informationen in Wörterbüchern übersichtlich zu gruppieren, und deque, um Elemente effizient zu beiden Seiten eines listenartigen Objekts hinzuzufügen.

      In diesem Turorial arbeiten wir in erster Linie mit einem Bestand von Fischen, den wir modifizieren müssen, wenn Fische zu einem fiktiven Aquarium hinzugefügt oder aus diesem entfernt werden.

      Voraussetzungen

      Um dieses Tutorial optimal zu nutzen, wird empfohlen, sich mit den Tupel-, Wörterbuch- und Listendatentypen vertraut zu machen; sowohl mit deren Syntax als auch mit der Art und Weise, Daten von ihnen abzurufen. Sie können für die notwendigen Hintergrundinformationen diese Tutorials durchsehen:

      Hinzufügen von benannten Feldern zu Tupeln

      Python-Tupeln sind eine unwandelbare oder unveränderliche, geordnete Sequenz von Elementen. Tupel werden häufig für die Darstellung von Spaltendaten verwendet, beispielsweise für Zeilen aus einer CSV-Datei oder Reihen aus einer SQL-Datenbank. Ein Aquarium könnte seinen Bestand an Fischen als eine Reihe von Tupeln erfassen.

      Ein individueller Fischtupel:

      ("Sammy", "shark", "tank-a")
      

      Dieses Tupel besteht aus drei Zeichenfolgenelementen.

      Das Tupel ist zwar in gewisser Weise nützlich, aber es gibt nicht klar an, wofür jedes seiner Felder steht. In Wirklichkeit ist Element 0 ein Name, Element 1 eine Spezies und Element 2 das Haltebecken.

      Erläuterung der Fischtupelfelder:

      Name Spezies Becken
      Sammy shark tank-a

      Diese Tabelle verdeutlicht, dass jedes der drei Elemente des Tupels eine klare Bedeutung hat.

      Mit namedtuple aus dem collections-Modul können Sie jedem Element eines Tupels explizite Namen hinzufügen, um diese Bedeutungen in Ihrem Python-Programm klarzustellen.

      Wir verwenden namedtuple zum Erstellen einer Klasse, die jedes Element des Fischtupels klar benennt:

      from collections import namedtuple
      
      Fish = namedtuple("Fish", ["name", "species", "tank"])
      

      from collections import namedtuple gibt Ihrem Python-Programm Zugriff auf die Factoryfunktion namedtuple. Der Funktionsaufruf namedtuple() gibt eine Klasse zurück, die an den Namen Fish gebunden ist. Die Funktion namedtuple() hat zwei Argumente: den gewünschten Namen unserer neuen Klasse "Fish" und eine Liste mit benannten Elementen ["name", "species", "tank"].

      Wir können die Fish-Klasse verwenden, um das Fischtupel von vorhin zu repräsentieren:

      sammy = Fish("Sammy", "shark", "tank-a")
      
      print(sammy)
      

      Wenn wir diesen Code ausführen, sehen wir die folgende Ausgabe:

      Output

      Fish(name="Sammy", species="shark", tank='tank-a')

      sammy wird mit der Fish-Klasse instanziiert. sammy ist ein Tupel mit drei klar benannten Elementen.

      Auf die Felder von sammy kann über ihren Namen oder mit einem traditionellen Tupelindex zugegriffen werden:

      print(sammy.species)
      print(sammy[1])
      

      Wenn wir diese beiden print-Aufrufe ausführen, sehen wir die folgende Ausgabe:

      Output

      shark shark

      Der Zugriff auf .species gibt denselben Wert zurück wie der Zugriff auf das zweite Element von sammy mit [1].

      Die Verwendung von namedtuple aus dem collections-Modul macht Ihr Programm lesbarer, wobei die wichtigen Eigenschaften eines Tupels (dass sie unveränderlich und geordnet sind) bewahrt bleiben.

      Darüber hinaus fügt die Factoryfunktion namedtuple mehrere zusätzliche Methoden zu Instanzen von Fish hinzu.

      Verwenden Sie ._asdict(), um eine Instanz in ein Wörterbuch zu konvertieren:

      print(sammy._asdict())
      

      Wenn wir print ausführen, sehen Sie eine Ausgabe wie die folgende:

      Output

      {'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}

      Das Aufrufen von .asdict() auf sammy gibt ein Wörterbuch zurück, das jedem der drei Feldnamen ihre entsprechenden Werte zuordnet.

      Python-Versionen, die älter als 3.8 sind, geben diese Zeile möglicherweise etwas anders aus. Sie könnten beispielsweise ein OrderedDict anstelle des hier gezeigten, einfachen Wörterbuchs sehen.

      Anmerkung: In Python werden Methoden mit vorangehenden Unterstrichen gewöhnlich als „privat“ eingestuft. Weitere Methoden, die von namedtuple bereitgestellt werden (wie _asdict(), ._make(), ._replace(), usw.), sind jedoch öffentlich.

      Sammeln von Daten in einem Wörterbuch

      Es ist oft nützlich, Daten in Python-Wörterbüchern zu sammeln. defaultdict aus dem collections-Modul kann uns helfen, Informationen schnell und übersichtlich in Wörterbüchern zusammenzustellen.

      defaultdict gibt nie einen KeyError aus. Wenn kein Schlüssel vorhanden ist, fügt defaultdict stattdessen einfach einen Platzhalterwert ein und gibt ihn zurück:

      from collections import defaultdict
      
      my_defaultdict = defaultdict(list)
      
      print(my_defaultdict["missing"])
      

      Wenn wir diesen Code ausführen, sehen wir eine Ausgabe wie die folgende:

      Output

      []

      defaultdict fügt einen Platzhalterwert ein und gibt ihn zurück, anstatt einen KeyError auszugeben. In diesem Fall haben wir den Platzhalterwert als Liste angegeben.

      Reguläre Wörterbücher hingegen geben bei fehlenden Schlüsseln einen KeyError aus:

      my_regular_dict = {}
      
      my_regular_dict["missing"]
      

      Wenn wir diesen Code ausführen, sehen wir eine Ausgabe wie die folgende:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'missing'

      Das reguläre Wörterbuch my_regular_dict gibt einen KeyError aus, wenn wir versuchen, auf einen Schlüssel zuzugreifen, der nicht vorhanden ist.

      defaultdict verhält sich anders als ein reguläres Wörterbuch. Statt einen KeyError auf einen fehlenden Schlüssel auszugeben, ruft defaultdict den Platzhalterwert ohne Argumente auf, um ein neues Objekt zu erstellen. In diesem Fall list(), um eine leere Liste zu erstellen.

      Um mit unserem fiktiven Aquarium-Beispiel fortzufahren, nehmen wir an, wir hätten eine Liste von Fischtupeln, die den Bestand eines Aquariums repräsentieren:

      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      

      Es gibt drei Fische in dem Aquarium – Name, Spezies und Haltebecken sind in diesen drei Tupeln notiert.

      Unser Ziel ist es, unseren Bestand nach Becken zu organisieren. Wir wollen die Liste der in jedem Becken vorhandenen Fische kennen. Anders ausgedrückt: Wir wollen ein Wörterbuch, das "tank-a" ["Jamie", "Mary"] und "tank-b" ["Jamie"] zuordnet.

      Wir können defaultdict verwenden, um den Fisch nach Becken zu gruppieren:

      from collections import defaultdict
      
      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      fish_names_by_tank = defaultdict(list)
      for name, species, tank in fish_inventory:
          fish_names_by_tank[tank].append(name)
      
      print(fish_names_by_tank)
      

      Nach Ausführung dieses Codes sehen wir die folgende Ausgabe:

      Output

      defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})

      fish_names_by_tank wird als ein defaultdict deklariert, das standardmäßig list() einfügt, anstatt einen KeyError auszugeben. Da dies garantiert, dass jeder Schlüssel in fish_names_by_tank auf eine list verweist, können wir frei .append() aufrufen, um Namen zu der Liste jedes Beckens hinzuzufügen.

      defaultdict hilft Ihnen hier, weil es die Wahrscheinlichkeit unerwarteter KeyErrors reduziert. Die Reduzierung der unerwarteten KeyErrors bedeutet, dass Ihr Programm klarer und mit weniger Zeilen geschrieben werden kann. Konkreter gesagt: Mit dem defaultdict-Idiom können Sie manuelles Instanziieren einer leeren Liste für jedes Becken vermeiden.

      Ohne defaultdict hätte der for-Schleifenkörper möglicherweise eher wie folgt ausgesehen:

      More Verbose Example Without defaultdict

      ...
      
      fish_names_by_tank = {}
      for name, species, tank in fish_inventory:
          if tank not in fish_names_by_tank:
            fish_names_by_tank[tank] = []
          fish_names_by_tank[tank].append(name)
      

      Die Verwendung eines regulären Wörterbuchs (statt eines defaultdict) bedeutet, dass der for-Schleifenkörper immer das Vorhandensein des gegebenen tank in fish_names_by_tank überprüfen muss. Erst nachdem wir überprüft haben, dass tank bereits in fish_names_by_tank vorhanden ist, oder gerade mit einem [] initialisiert wurde, können wir den Fischnamen ergänzen.

      defaultdict kann dazu beitragen, beim Füllen der Wörterbücher den Standardcode zu reduzieren, da es nie einen KeyError ausgibt.

      Verwenden von deque zum effizienten Hinzufügen von Elementen zu beiden Seiten einer Sammlung

      Python-Listen sind eine wandelbare oder veränderliche, geordnete Sequenz von Elementen. Python kann Listen in konstanter Zeit ergänzen (die Länge der Liste hat keine Auswirkungen auf die Zeit, die zum Ergänzen benötigt wird), aber das Einfügen am Anfang einer Liste kann langsamer sein – die Zeitdauer erhöht sich beim Anwachsen der Liste.

      Im Sinne der Big-O-Notation ist das Ergänzen einer Liste ein O(1)-Vorgang mit konstanter Zeit. Im Gegensatz ist das Einfügen am Anfang einer Liste langsamer mit einer O(n)​​​-Leistung.

      Anmerkung: Softwareingenieure messen die Leistung von Vorgängen oft mit der sogenannten „Big O“-Notation. Wenn die Größe einer Eingabe keine Auswirkungen auf die Zeit hat, die zum Ausführen eines Vorgangs benötigt wird, spricht man von einem Ablauf in konstanter Zeit oder O(1) („Big O von 1“). Wie Sie oben gelernt haben, kann Python Listen mit konstanter Zeitleistung, auch als O(1) bekannt, ergänzen.

      Manchmal beeinflusst die Größe einer Eingabe direkt die Zeit, die zum Ausführen eines Vorgangs benötigt wird. Das Einfügen am Anfang einer Python-Liste zum Beispiel läuft umso langsamer ab, je mehr Elemente in der Liste vorhanden sind. Die Big-O-Notation verwendet den Buchstaben n, um die Größe der Eingabe darzustellen. Das bedeutet, dass das Hinzufügen von Elementen am Anfang einer Python-Liste in „linearer Zeit“ oder O(n) („Big O von n“) abläuft.

      Im Allgemeinen sind O(1)-Vorgänge schneller als O(n)-Vorgänge.

      Wir können am Anfang einer Python-Liste einfügen:

      favorite_fish_list = ["Sammy", "Jamie", "Mary"]
      
      # O(n) performance
      favorite_fish_list.insert(0, "Alice")
      
      print(favorite_fish_list)
      

      Wenn wir Folgendes ausführen, sehen wir eine Ausgabe wie die folgende:

      Output

      ['Alice', 'Sammy', 'Jamie', 'Mary']

      Die .insert(index, object)-Methode in der Liste ermöglicht uns, „Alice“ am Anfang von favorite_fish_list einzufügen. Jedoch hat das Einfügen am Anfang einer Liste eine O(n)-Leistung. Wenn die Länge der favorite_fish_list wächst, wird die Zeit, um einen Fisch am Anfang der Liste einzufügen, proportional anwachsen und immer länger dauern.

      deque (ausgesprochen „Deck“) aus dem collections-Modul ist ein listenähnliches Objekt, das es uns ermöglicht, Elemente am Anfang oder Ende einer Sequenz mit konstanter Zeit (O(1))-Leistung einzufügen.

      Geben Sie ein Element am Anfang eines deque ein:

      from collections import deque
      
      favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
      
      # O(1) performance
      favorite_fish_deque.appendleft("Alice")
      
      print(favorite_fish_deque)
      

      Nach Ausführung dieses Codes sehen wir die folgende Ausgabe:

      Output

      deque(['Alice', 'Sammy', 'Jamie', 'Mary'])

      Wir können ein deque anhand einer bereits vorhandenen Sammlung von Elementen instanziieren, in diesem Fall einer Liste mit drei bevorzugten Fischnamen. Das Aufrufen der appendleft-Methode von favorite_fish_deque ermöglicht uns, ein Element am Anfang unserer Sammlung mit O(1)-Leistung einzufügen. O(1)-Leistung bedeutet, dass die Zeit, die zum Hinzufügen eines Elements am Anfang von favorite_fish_deque benötigt wird, nicht zunimmt, selbst wenn favorite_fish_deque Tausende oder Millionen von Elementen enthält.

      Anmerkung: Obwohl deque Einträge am Anfang einer Sequenz effizienter als eine Liste hinzufügt, führt deque nicht alle seine Vorgänge effizienter als eine Liste aus. Beispielsweise hat das Zugreifen auf ein zufälliges Element in einem deque eine O(n)-Leistung, das Zugreifen auf ein zufälliges Element in einer Liste jedoch eine O(1)-Leistung Verwenden Sie deque, wenn es wichtig ist, Elemente schnell zu beiden Seiten Ihrer Sammlung hinzuzufügen oder zu entfernen. Ein vollständiger Vergleich der Zeitleistung ist auf Pythons Wiki verfügbar.

      Zusammenfassung

      Das collections-Modul ist ein leistungsfähiger Teil der Python-Standardbibliothek, mit dem Sie übersichtlich und effizient Daten bearbeiten können. Dieses Tutorial behandelte drei der Klassen, die vom collections-Modul bereitgestellt werden, einschließlich namedtuple, defaultdict und deque.

      Nun können Sie die Dokumentation des collection-Moduls nutzen, um mehr über andere verfügbare Klassen und Dienstprogramme zu erfahren. Um im Allgemeinen mehr über Python zu erfahren, können Sie unsere Tutorialreihe Codieren in Python 3 lesen.



      Source link