Modulares Programmieren mit Funktionen

Beginner

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

Einführung

In diesem Abschnitt wird das Konzept von Modulen und das Arbeiten mit Funktionen, die über mehrere Dateien hinausgehen, vorgestellt.

Dies ist ein Guided Lab, das schrittweise Anweisungen bietet, um Ihnen beim Lernen und Üben zu helfen. Befolgen Sie die Anweisungen sorgfältig, um jeden Schritt abzuschließen und praktische Erfahrungen zu sammeln. Historische Daten zeigen, dass dies ein Labor der Stufe Anfänger mit einer Abschlussquote von 82% ist. Es hat eine positive Bewertungsrate von 100% von den Lernenden erhalten.

Module und Import

Jede Python-Quelldatei ist ein Modul.

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

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

## program.py
import foo

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

Namensräume

Ein Modul ist eine Sammlung von benannten Werten und wird manchmal als Namensraum bezeichnet. Die Namen sind alle globalen Variablen und Funktionen, die in der Quelldatei definiert sind. Nach dem Import wird der Modulname als Präfix verwendet. Daher der Namensraum.

import foo

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

Der Modulname ist direkt an den Dateinamen gebunden (foo -> foo.py).

Globale Definitionen

Alles, was im globalen Bereich definiert ist, füllt den Modulnamenraum. Betrachten Sie zwei Module, die die gleiche Variable x definieren.

## foo.py
x = 42
def grok(a):
 ...
## bar.py
x = 37
def spam(a):
 ...

In diesem Fall beziehen sich die x-Definitionen auf unterschiedliche Variablen. Eine ist foo.x und die andere ist bar.x. Verschiedene Module können die gleichen Namen verwenden, und diese Namen werden nicht miteinander in Konflikt geraten.

Module sind isoliert.

Module als Umgebungen

Module bilden eine umschließende Umgebung für den gesamten darin definierten Code.

## foo.py
x = 42

def grok(a):
    print(x)

Globale Variablen sind immer an das umschließende Modul (selbe Datei) gebunden. Jede Quelldatei ist ein eigenes kleines Universum.

Modulausführung

Wenn ein Modul importiert wird, werden alle Anweisungen im Modul nacheinander ausgeführt, bis das Ende der Datei erreicht ist. Die Inhalte des Modulnamensraums sind alle globalen Namen, die am Ende des Ausführungsprozesses noch definiert sind. Wenn es Skriptanweisungen gibt, die Aufgaben im globalen Bereich ausführen (Drucken, Erstellen von Dateien usw.), werden Sie sie beim Import ausgeführt sehen.

import as-Anweisung

Sie können den Namen eines Moduls ändern, wenn Sie es importieren:

import math as m
def rectangular(r, theta):
    x = r * m.cos(theta)
    y = r * m.sin(theta)
    return x, y

Es funktioniert genauso wie ein normaler Import. Es benennt das Modul nur in dieser Datei um.

from Modul importieren

Dies wählt ausgewählte Symbole aus einem Modul aus und macht sie lokal verfügbar.

from math import sin, cos

def rectangular(r, theta):
    x = r * cos(theta)
    y = r * sin(theta)
    return x, y

Dadurch können Teile eines Moduls verwendet werden, ohne dass der Modulprefix eingegeben werden muss. Dies ist für häufige Namen nützlich.

Bemerkungen zum Importieren

Variationen beim Importieren ändern die Art und Weise, wie Module funktionieren, nicht.

import math
## vs
import math as m
## vs
from math import cos, sin
...

Insbesondere führt import immer die gesamte Datei aus und Module bleiben immer noch isolierte Umgebungen.

Die import modul as-Anweisung ändert nur den Namen lokal. Die from math import cos, sin-Anweisung lädt hinter den Kulissen immer noch das gesamte math-Modul. Es kopiert lediglich die cos- und sin-Namen aus dem Modul in den lokalen Namensraum, nachdem es fertig ist.

Modulladen

Jedes Modul lädt und führt nur einmal aus. Hinweis: Wiederholte Imports geben lediglich einen Verweis auf das zuvor geladene Modul zurück.

sys.modules ist ein Wörterbuch aller geladenen Module.

>>> import sys
>>> sys.modules.keys()
['copy_reg', '__main__','site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath',...]
>>>

Vorsicht: Ein häufiger Irrtum tritt auf, wenn Sie einen import-Befehl nach Änderung des Quellcodes eines Moduls wiederholen. Aufgrund des Modulcaches sys.modules geben wiederholte Imports immer das zuvor geladene Modul zurück – auch wenn eine Änderung vorgenommen wurde. Der sicherste Weg, geänderter Code in Python zu laden, ist es, den Interpreter zu beenden und neu zu starten.

Das Finden von Modulen

Python konsultiert eine Pfadliste (sys.path), wenn es nach Modulen sucht.

>>> import sys
>>> sys.path
[
  '',
  '/usr/local/lib/python36/python36.zip',
  '/usr/local/lib/python36',
...
]

Das aktuelle Arbeitsverzeichnis steht normalerweise zuerst in der Liste.

Modulsuchpfad

Wie erwähnt, enthält sys.path die Suchpfade. Sie können diese manuell anpassen, wenn erforderlich.

import sys
sys.path.append('/project/foo/pyfiles')

Pfade können auch über Umgebungsvariablen hinzugefügt werden.

% env PYTHONPATH=/project/foo/pyfiles python3
Python 3.6.0 (default, Feb 3 2017, 05:53:21)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
>>> import sys
>>> sys.path
['','/project/foo/pyfiles',...]

Allgemein sollte es nicht erforderlich sein, den Modulsuchpfad manuell anzupassen. Es kann jedoch vorkommen, wenn Sie versuchen, Python-Code zu importieren, der sich an einem ungewöhnlichen Ort befindet oder nicht von dem aktuellen Arbeitsverzeichnis aus leicht zugänglich ist.

Für diese Übung zu Modulen ist es von entscheidender Wichtigkeit, sicherzustellen, dass Sie Python in einer geeigneten Umgebung ausführen. Module stellen für neue Programmierer oft Probleme im Zusammenhang mit dem aktuellen Arbeitsverzeichnis oder mit den Pfadeinstellungen von Python dar. Für diesen Kurs wird angenommen, dass Sie all Ihren Code im Verzeichnis ~/project schreiben. Um die besten Ergebnisse zu erzielen, sollten Sie sich auch im selben Verzeichnis befinden, wenn Sie den Interpreter starten. Wenn nicht, müssen Sie sicherstellen, dass ~/project zu sys.path hinzugefügt wird.

Übung 3.11: Modulimporte

Im Abschnitt 3 haben wir eine allgemein nutzbare Funktion parse_csv() erstellt, um die Inhalte von CSV-Datendateien zu analysieren.

Jetzt werden wir sehen, wie man diese Funktion in anderen Programmen verwenden kann. Beginnen Sie zunächst in einem neuen Shell-Fenster. Navigieren Sie zum Ordner, in dem Sie alle Ihre Dateien haben. Wir werden sie importieren.

Starten Sie die interaktive Python-Betriebsmode.

$ python3
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

Sobald Sie das getan haben, versuchen Sie, einige der zuvor geschriebenen Programme zu importieren. Sie sollten genauso wie zuvor deren Ausgabe sehen. Um zu betonen: Beim Importieren eines Moduls wird dessen Code ausgeführt.

>>> import bounce
... Ausgabe anzeigen...
>>> import mortgage
... Ausgabe anzeigen...
>>> import report
... Ausgabe anzeigen...
>>>

Wenn nichts davon funktioniert, laufen Sie wahrscheinlich Python im falschen Verzeichnis. Versuchen Sie jetzt, Ihr fileparse-Modul zu importieren und Hilfe zu erhalten.

>>> import fileparse
>>> help(fileparse)
... Ausgabe ansehen...
>>> dir(fileparse)
... Ausgabe ansehen...
>>>

Versuchen Sie, das Modul zum Lesen einiger Daten zu verwenden:

>>> portfolio = fileparse.parse_csv('/home/labex/project/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... Ausgabe ansehen...
>>> pricelist = fileparse.parse_csv('/home/labex/project/prices.csv',types=[str,float], has_headers=False)
>>> pricelist
... Ausgabe ansehen...
>>> prices = dict(pricelist)
>>> prices
... Ausgabe ansehen...
>>> prices['IBM']
106.28
>>>

Versuchen Sie, eine Funktion zu importieren, so dass Sie den Modulnamen nicht mehr angeben müssen:

>>> from fileparse import parse_csv
>>> portfolio = parse_csv('/home/labex/project/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... Ausgabe ansehen...
>>>

Übung 3.12: Verwenden Ihres Bibliotheksmoduls

Im Abschnitt 2 haben Sie ein Programm report.py geschrieben, das einen Aktienbericht wie diesen erzeugt hat:

      Name     Anteile      Preis     Änderung
---------- ---------- ---------- ----------
        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

Nehmen Sie dieses Programm und ändern Sie es so, dass alle Verarbeitung der Eingabedateien mit Funktionen aus Ihrem fileparse-Modul erfolgt. Dazu importieren Sie fileparse als Modul und ändern Sie die Funktionen read_portfolio() und read_prices(), um die Funktion parse_csv() zu verwenden.

Verwenden Sie das interaktive Beispiel am Anfang dieser Übung als Anleitung. Danach sollten Sie genau die gleiche Ausgabe wie zuvor erhalten.

Übung 3.13: Absichtlich leer gelassen (überspringen)

Übung 3.14: Verwenden weiterer Bibliotheksimporte

Im Abschnitt 1 haben Sie ein Programm pcost.py geschrieben, das ein Portfolio auslas und dessen Kosten berechnete.

>>> import pcost
>>> pcost.portfolio_cost('/home/labex/project/portfolio.csv')
44671.15
>>>

Ändern Sie die Datei pcost.py so, dass es die Funktion report.read_portfolio() verwendet.

Kommentar

Wenn Sie mit dieser Übung fertig sind, sollten Sie drei Programme haben. fileparse.py, das eine allgemein nutzbare Funktion parse_csv() enthält. report.py, das einen schönen Bericht erzeugt, aber auch die Funktionen read_portfolio() und read_prices() enthält. Und schließlich pcost.py, das die Portfolio-Kosten berechnet, aber die für das report.py-Programm geschriebene Funktion read_portfolio() verwendet.

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Modul-Labor abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.