Wiederkehrende Abläufe erneut verwenden - wie funktionierts?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
The Bang 2
User
Beiträge: 14
Registriert: Montag 11. März 2013, 12:30

Guten Morgen zusammen,

ich beschäftige mich seit kurzem mit Python und schreibe gerade an einem Script. Dieser verbindet sich via FTP mit verschiedenen Servern und löscht leere Ordner mit einem bestimmten Anfang.
Dank Hilfe aus dem Forum konnte ich das Ding zum laufen bringen und dies sieht aktuell so aus:

Code: Alles auswählen

# Importiere Libs
from ftplib import FTP
import time
#Variablen fuer Verbindung
user = 'abb'
password = '007'
targetdir = '/'
searchdef = 'BCK'
errorpassed = '0'

#Lese IP und Namen aus Hostliste ein
with open("hostlist.txt") as input_raw:
    input = [s for s in input_raw if s.startswith('192')]
    hostlist = [line.strip() for line in input]
    input_raw.close()
    print('Gefundene hosts: ', hostlist)

#Login auf Server
for host in hostlist:
    try:
        print("Verbinde zu IP", host)
        ftp = FTP(host)
        ftp.login(user, password)
        ftp.cwd(targetdir)
        #Werte Daten nach Beginn BCK aus
        units = ftp.nlst()
        units = [s for s in units if s.startswith('BCK')]
        numbers_bck = len(units)
        print("Anzahl gefundene Backups:", len(units))

        #Loesche gefundene Backups
        for dirname in units:
            try:
                ftp.rmd(dirname)
                print ("Loesche Backup", dirname)
            except Exception:
                #Fehlerbehandlung
                error = ('Verzeichnis nicht leer: ' + dirname + ' auf IP ' + host)
                print(error)
                errortime = time.strftime("%d.%m.%Y / %H:%M:%S")
                text_file = open("errorlog.txt", "a")
                text_file.write((errortime + '\n' + error) + '\n')
                text_file.close()
                errorpassed = 1
    except Exception:
        error = ('Server ' + host + ' nicht erreichbar')
        print(error)
        errortime = time.strftime("%d.%m.%Y / %H:%M:%S")
        text_file = open("errorlog.txt", "a")
        text_file.write((errortime + '\n' + error) + '\n')
        text_file.close()
        errorpassed = 1
    ftp.quit()

if errorpassed == 1:
    print('Es sind Fehler aufgetreten, bitte Log pruefen!')
Dies funktioniert soweit, allerdings missfällt mir die wiederkehrende Verwendung von

Code: Alles auswählen

        errortime = time.strftime("%d.%m.%Y / %H:%M:%S")
        text_file = open("errorlog.txt", "a")
        text_file.write((errortime + '\n' + error) + '\n')
        text_file.close()
Nun kenne ich es aus der "nennen-wir-es-mal"-Programmiersprache Rapid dass so etwas als Funktion definiert und dann nach belieben aufgerufen werden kann. Nach etwas Literatur im Netz bin ich aber nicht wesentlich schlauer - soweit ich das vestanden habe kann ich Funktionen folgendermaßen definieren:

Code: Alles auswählen

def errorhandling():
        errortime = time.strftime("%d.%m.%Y / %H:%M:%S")
        text_file = open("errorlog.txt", "a")
        text_file.write((errortime + '\n' + error) + '\n')
        text_file.close()
Allerdings verstehe ich nicht wie ich diese Funktion im eigentlichen Script aufrufen kann - wie hat das dann auszusehen? Habe ich das überhaupt richtig verstanden?
Zuletzt geändert von Anonymous am Dienstag 12. März 2013, 10:50, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Deine Funktion braucht als Parameter die Fehlermeldung, die bei Dir "error" heisst. Das print kannst Du mit in die Funktion ziehen:

Code: Alles auswählen

def errorhandling(error):
    print(error)
    errortime = time.strftime("%d.%m.%Y / %H:%M:%S")
    text_file = open("errorlog.txt", "a")
    text_file.write((errortime + '\n' + error) + '\n')
    text_file.close()
Diese Funktion rufst Du im Skript einfach per Namen auf:

Code: Alles auswählen

error = 'Server ' + host + ' nicht erreichbar'
errorhandling(error)
Ohne jetzt alle Verbesserungsmöglichkeiten zu listen, hier erst einmal die aus meiner Sicht wichtigste: fange die Exceptions explizit ab und nicht allgemein. Sonst kann es sein, dass Du den wahren Grund einer Ausnahme nicht erfährst und Dein Programm nicht korrekt abändern kannst.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Du müsstest den Funktionskopf mit einem Argument definieren. Etwa so:

Code: Alles auswählen

def log_error(message):
    with open(LOGFILE_PATH, 'a') as logfile:
        logfile.write(message)

# und an anderer Stelle dann als Aufruf
log_error('Fehler xyz ist aufgetreten')
`errortime` und weitere komplexe Dinge hab ich hier der Einfachheit halber mal weggelassen.

Meine dringende Empfehlung wäre auch, sich das logging-Modul mal näher anzusehen. Damit kannst du dir das ganze Drumherum weitesgehend ersparen und dich stattdessen nur auf's eigentliche Absenden der zu loggenden Meldungen konzentrieren.
The Bang 2
User
Beiträge: 14
Registriert: Montag 11. März 2013, 12:30

Okay, ich werde mir beide Möglichkeiten näher ansehen - vielen Dank soweit :)
BlackJack

@The Bang 2: Anmerkungen zum Programm:

`errorpassed` soll offenbar ein Wahrheitswert sein. Dafür gibt es in Python einen eigenen Datentyp `bool` mit den Werten `True` und `False`. Den Namen anfänglich an eine Zeichenkette und dann an Zahlen zu binden ist verwirrend.

`searchdef` und `numbers_bck` werden definiert, aber nicht verwendet.

`input` ist der Name einer eingebauten Funktion, den Du verdeckst. Der Name ist auch ein wenig allgemein. Letztlich ist der Zwischenschritt nicht wirklich nötig, weil man die beiden „list comprehensions” problemlos zu einer zusammenfassen kann.

Wenn man die ``with``-Anweisung mit Dateien verwendet, braucht man kein explizites `close()` mehr.

Der konkrete Datentyp sollte nicht mit im Namen kodiert werden. Es passiert häufig, dass man den Typ ändert, und dann entweder alle Namen ändern muss, oder falsche und irreführende Namen im Programm hat.

Überarbeitet (und ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
import time
from ftplib import FTP


def log_error(message, _error):
    #
    # TODO Argument `_error` verwenden um den *tatsächlichen* Grund für den
    #   Fehler protokollieren zu können.
    #
    print(message)
    with open('errorlog.txt', 'a') as log_file:
        log_file.write(
            '{0}\n{1}\n'.format(time.strftime('%d.%m.%Y / %H:%M:%S'), message)
        )


def main():
    # 
    # Verbindungsdaten.
    # 
    user = 'abb'
    password = '007'
    targetdir = '/'
    searchdef = 'BCK'
    errors_occurred = False
    # 
    # Lese IP und Namen aus Hostliste ein.
    # 
    with open('hostlist.txt') as lines:
        hosts = [s.strip() for s in lines if s.startswith('192')]
        print('Gefundene hosts:', hosts)
    # 
    # Login auf Server.
    # 
    for host in hosts:
        try:
            print('Verbinde zu IP', host)
            ftp = FTP(host)
            ftp.login(user, password)
            ftp.cwd(targetdir)
            # 
            # Werte Daten nach Beginn `searchdef` aus.
            # 
            units = [s for s in ftp.nlst() if s.startswith(searchdef)]
            print('Anzahl gefundene Backups:', len(units))
            # 
            # Loesche gefundene Backups.
            # 
            for dirname in units:
                try:
                    print('Loesche Backup', dirname)
                    ftp.rmd(dirname)
                except Exception as error:
                    log_error(
                        'Verzeichnis nicht leer: {0} auf IP {1}'.format(
                            dirname, host
                        ),
                        error
                    )
                    errors_occurred = True
        except Exception as error:
            log_error('Server {0} nicht erreichbar'.format(host), error)
            errors_occurred = True
        ftp.quit()

    if errors_occurred:
        print('Es sind Fehler aufgetreten, bitte Log pruefen!')
Antworten