Das Organisieren größerer Python-Programme

PythonPythonBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

Wenn Sie ein größeres Programm schreiben, möchten Sie es nicht wirklich als eine große Sammlung von eigenständigen Dateien auf der obersten Ebene organisieren. Dieser Abschnitt stellt das Konzept eines Pakets vor.

Module

Jede Python-Quelldatei ist ein Modul.

## foo.py
def grok(a):
 ...
def spam(b):
 ...

Eine import-Anweisung lädt und führt ein Modul aus.

## program.py
import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

Pakete vs. Module

Für größere Code-Sammlungen ist es üblich, Module in ein Paket zu organisieren.

## Von diesem
pcost.py
report.py
fileparse.py

## Zu diesem
porty/
    __init__.py
    pcost.py
    report.py
    fileparse.py

Wählen Sie einen Namen und erstellen Sie ein oberstes Verzeichnis. porty im obigen Beispiel (klarerweise ist das Wählen dieses Namens der wichtigste erste Schritt).

Fügen Sie eine __init__.py-Datei in das Verzeichnis hinzu. Sie kann leer sein.

Legen Sie Ihre Quelltexte in das Verzeichnis ab.

Verwendung eines Pakets

Ein Paket dient als Namensraum für Imports.

Dies bedeutet, dass es jetzt Mehr-Ebene-Imports gibt.

import porty.report
port = porty.report.read_portfolio('portfolio.csv')

Es gibt auch andere Variationen von Importanweisungen.

from porty import report
port = report.read_portfolio('portfolio.csv')

from porty.report import read_portfolio
port = read_portfolio('portfolio.csv')

Zwei Probleme

Es gibt zwei Hauptprobleme mit diesem Ansatz.

  • Imports zwischen Dateien im selben Paket brechen.
  • Hauptskripte, die innerhalb des Pakets platziert werden, brechen.

Also, im Grunde alles bricht. Aber abgesehen davon funktioniert es.

Problem: Imports

Imports zwischen Dateien im selben Paket müssen jetzt den Paketnamen im Import enthalten. Denken Sie sich die Struktur ein.

porty/
    __init__.py
    pcost.py
    report.py
    fileparse.py

Verändertes Importbeispiel.

from porty import fileparse

def read_portfolio(filename):
    return fileparse.parse_csv(...)

Alle Imports sind absolut, nicht relativ.

import fileparse    ## Bricht. fileparse nicht gefunden

...

Relative Imports

Anstatt direkt den Paketnamen zu verwenden, können Sie . verwenden, um auf das aktuelle Paket zu verweisen.

from. import fileparse

def read_portfolio(filename):
    return fileparse.parse_csv(...)

Syntax:

from. import modname

Dies macht es einfach, das Paket umzubenennen.

Problem: Main Scripts

Das Ausführen eines Paket-Untermoduls als Hauptskript bricht.

$ python porty/pcost.py ## Bricht
...

Grund: Sie führen Python auf einer einzelnen Datei aus und Python erkennt die restliche Paketstruktur nicht richtig (sys.path ist falsch).

Alle Imports brechen. Um das zu beheben, müssen Sie Ihr Programm auf eine andere Weise ausführen, indem Sie die Option -m verwenden.

$ python -m porty.pcost ## Funktioniert
...

__init__.py-Dateien

Der primäre Zweck dieser Dateien besteht darin, Module zusammenzusetzen.

Beispiel: Zusammenführen von Funktionen

## porty/__init__.py
from.pcost import portfolio_cost
from.report import portfolio_report

Dadurch erscheinen die Namen auf der Hauptebene, wenn importiert wird.

from porty import portfolio_cost
portfolio_cost('portfolio.csv')

Anstatt die mehrstufigen Imports zu verwenden.

from porty import pcost
pcost.portfolio_cost('portfolio.csv')

Ein weiterer Lösung für Skripte

Wie erwähnt, müssen Sie jetzt -m package.module verwenden, um Skripte innerhalb Ihres Pakets auszuführen.

$ python3 -m porty.pcost portfolio.csv

Es gibt eine weitere Möglichkeit: Schreiben Sie ein neues Hauptskript.

#!/usr/bin/env python3
## pcost.py
import porty.pcost
import sys
porty.pcost.main(sys.argv)

Dieses Skript befindet sich außerhalb des Pakets. Beispielsweise betrachten Sie die Verzeichnisstruktur:

pcost.py       ## Hauptskript
porty/         ## Paketverzeichnis
    __init__.py
    pcost.py
 ...

Anwendungsstruktur

Die Codeorganisation und die Dateistruktur sind entscheidend für die Wartbarkeit einer Anwendung.

Es gibt keine "eines-fits-all"-Methode für Python. Ein Struktur, die jedoch für viele Probleme funktioniert, sieht so aus.

porty-app/
  README.txt
  script.py         ## SKRIPT
  porty/
    ## BIBLIOTHEKSCODE
    __init__.py
    pcost.py
    report.py
    fileparse.py

Das oberste Level porty-app ist ein Container für alles andere - Dokumentation, oberste Level Skripte, Beispiele usw.

Wiederholen Sie, dass die obersten Level Skripte (falls vorhanden) außerhalb des Code-Pakets existieren müssen. Ein Level höher.

#!/usr/bin/env python3
## porty-app/script.py
import sys
import porty

porty.report.main(sys.argv)

Zu diesem Zeitpunkt haben Sie ein Verzeichnis mit mehreren Programmen:

pcost.py          ## berechnet die Portfolio-Kosten
report.py         ## Erstellt einen Bericht
ticker.py         ## Erzeugt einen Echtzeit-Aktien-Ticker

Es gibt eine Vielzahl von unterstützenden Modulen mit anderen Funktionen:

stock.py          ## Stock-Klasse
portfolio.py      ## Portfolio-Klasse
fileparse.py      ## CSV-Parsing
tableformat.py    ## Formatierte Tabellen
follow.py         ## Folgt einer Log-Datei
typedproperty.py  ## Typisierte Klassen-Eigenschaften

In dieser Übung werden wir den Code aufräumen und in ein gemeinsames Paket einfügen.

Übung 9.1: Erstellen eines einfachen Pakets

Erstellen Sie ein Verzeichnis namens porty/ und legen Sie alle obigen Python-Dateien darin ab. Erstellen Sie zusätzlich eine leere __init__.py-Datei und legen Sie sie im Verzeichnis ab. Sie sollten ein Verzeichnis mit Dateien wie dieses haben:

porty/
    __init__.py
    fileparse.py
    follow.py
    pcost.py
    portfolio.py
    report.py
    stock.py
    tableformat.py
    ticker.py
    typedproperty.py

Löschen Sie die Datei __pycache__, die sich in Ihrem Verzeichnis befindet. Dies enthält zuvor kompilierte Python-Module. Wir möchten von vorne beginnen.

Versuchen Sie, einige der Paketmodule zu importieren:

>>> import porty.report
>>> import porty.pcost
>>> import porty.ticker

Wenn diese Imports fehlschlagen, gehen Sie in die entsprechende Datei und ändern Sie die Modulimporte, um einen paketrelativen Import zu verwenden. Beispielsweise könnte ein Statement wie import fileparse wie folgt geändert werden:

## report.py
from. import fileparse

...

Wenn Sie ein Statement wie from fileparse import parse_csv haben, ändern Sie den Code wie folgt:

## report.py
from.fileparse import parse_csv

...

✨ Lösung prüfen und üben

Übung 9.2: Erstellen eines Anwendungsverzeichnisses

Das Einbringen Ihres gesamten Codes in ein "Paket" reicht für eine Anwendung oft nicht aus. Manchmal gibt es unterstützende Dateien, Dokumentation, Skripte und andere Dinge. Diese Dateien müssen außerhalb des oben erstellten porty/-Verzeichnisses existieren.

Erstellen Sie ein neues Verzeichnis namens porty-app. Verschieben Sie das in Übung 9.1 erstellte porty-Verzeichnis in dieses Verzeichnis. Kopieren Sie die Testdateien portfolio.csv und prices.csv in dieses Verzeichnis. Erstellen Sie zusätzlich eine README.txt-Datei mit Informationen über sich selbst. Ihr Code sollte jetzt wie folgt organisiert sein:

porty-app/
    portfolio.csv
    prices.csv
    README.txt
    porty/
        __init__.py
        fileparse.py
        follow.py
        pcost.py
        portfolio.py
        report.py
        stock.py
        tableformat.py
        ticker.py
        typedproperty.py

Um Ihren Code auszuführen, müssen Sie sicherstellen, dass Sie im obersten Level-Verzeichnis porty-app/ arbeiten. Beispielsweise von der Kommandozeile:

$ cd porty-app
$ python3
>>> import porty.report
>>>

Versuchen Sie, einige Ihrer vorherigen Skripte als Hauptprogramm auszuführen:

$ cd porty-app
$ python3 -m porty.report portfolio.csv prices.csv txt
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84

$

Übung 9.3: Oberste Ebene Skripte

Das Verwenden des Befehls python -m ist oft etwas ungewöhnlich. Möglicherweise möchten Sie ein oberstes Ebene Skript schreiben, das einfach mit den Besonderheiten von Paketen umgeht. Erstellen Sie ein Skript print-report.py, das den obigen Bericht erzeugt:

#!/usr/bin/env python3
## print-report.py
import sys
from porty.report import main
main(sys.argv)

Legen Sie dieses Skript im obersten Level-Verzeichnis porty-app/ ab. Stellen Sie sicher, dass Sie es an diesem Ort ausführen können:

$ cd porty-app
$ python3 print-report.py portfolio.csv prices.csv txt
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84

$

Ihr endgültiger Code sollte jetzt ungefähr so strukturiert sein:

porty-app/
    portfolio.csv
    prices.csv
    print-report.py
    README.txt
    porty/
        __init__.py
        fileparse.py
        follow.py
        pcost.py
        portfolio.py
        report.py
        stock.py
        tableformat.py
        ticker.py
        typedproperty.py
✨ Lösung prüfen und üben

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab zu Paketen abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.