Timer und loop

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
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Hallo in die Runde,

ich hätte da mal ein Problem ;)

Ich öffne in meinem Programm immer eine Datei (textX.txt), bearbeite diese und dann kommt die nächste.
Das ganze hängt in einer Endlosschleife, da dies immer laufen soll.

Nun würde ich gerne z.B. if Anweisung einbauen oder try/exception.
Falls die Datei zum lesen noch nicht da ist.
Nur das mit dem 'warte 5 min. und dann noch mal probieren'
bereitet mir Problemchen. Ich habe mir schon bisschen zur timer Funktion durchgelesen, aber so richtig habe ich das noch nicht hin bekommen.

Vielleicht hätte hier noch jemand nen Tip für mich.

Danke und Grüße,
Locke.

Code: Alles auswählen

# init Count
count = 0
# Loop forever
while True:  
  count = count + 1
  try:
    # open file
    path = 'C:\\text%s.txt'%count
    file = open (path, r)
    print '***   Begin reading file text%s.txt File   ***' % count  
    for line in file: 
      # hier lese ich die Datei aus
  except IOError:
    # warte 5 min und dann noch mal probieren
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Code: Alles auswählen

from time import sleep

FILE_TEMPLATE = 'C:\\text%s.txt'

def main():
    count = 0
    def open_and_do():
        count = count + 1
        try:
            # open file
            path = FILE_TEMPLATE % count
            file = open (path, 'r')
            print '***   Begin reading file text%s.txt File   ***' % count  
            for line in file: 
                do_stuff(line)
        except IOError:
            sleep(300)
            return open_and_do()

    while True:
        open_and_do()
Wobei ich das durchaus unsauber finde so.
Aber gut, wirst schon deine Gründe haben...
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Stimmt mit einer Funktion geht das ja einfach zu lösen, danke für die Hilfe.

Wieso findest du das ganze unsauber, bzw. was?
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Einfach über Dateien iterieren, die über nen Formatstring erstellt werden.....bäh.
Besorg dir lieber irgendwie die Liste dieser Dateien und iteriere darüber, das ist nicht so fehleranfällig.

Btw:
Lagere IMMER ALLE(!) Kontanten aus, wirklich immer!
Das spart einem so unglaublich viel Arbeit, wenn man später noch was ändert...
Eine einfache Variable zu ändern geht fix, mit einer RegExp-Ersetzung durch den ganzen Projektordner zu rattern ist da schon aufwändiger ;)
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Ja das mit den Konstanten, da verfalle ich so manchmal in die Schlamperei, wenn ich das so hin tippe.
Wenn alles läuft schaue ich mir immer noch mal alles an und versuche zu optimieren. Das optimieren nimmt auch meistens mehr Zeit in Anspruch :)

Das mit der Liste der Dateien ist schwer, da die Textdateien ja nicht statisch dort sind. Die Textdateien in dem Ordner werden halt immer mehr, daher würde eine Liste meines Erachtens keinen Sinn machen oder?
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Kontansten gehören an den Anfang oder ausgelagert, das Refactoring macht wirklich keinen Spaß, glaub mir...

Und wenn schon keine Liste, dann wenigstens ein ausgelagerter Generator:

Code: Alles auswählen

def file_gen(count=0)
    def gen():
        try:
            path = FILE_TEMPLATE % count
            return open (path, 'r')
        except IOError:
            sleep(300)
            return gen()

    while True:
        count += 1
        yield gen()
BlackJack

@audax: Unnötige Rekursion. Wenn das lange läuft und diese Ausnahme wirklich vorkommen, kann man sich damit das Programm wegen dem Rekursionslimit abschiessen.

@nordlocke: Wenn, dann würde ich es so schreiben:

Code: Alles auswählen

from itertools import count
from time import sleep


def main():
    for number in count(1):
        try:
            path = r'C:\text%s.txt' % number
            lines = open(path)
        except IOError:
            sleep(300)
        else:
            print '*** Begin reading file %s ***' % path
            for line in lines:
                pass
            lines.close()
Allerdings finde ich es komisch, dass nach der Wartezeit mit der nächsten Nummer weiter gemacht werden soll. Ist das Absicht? Und falls es sich hier um das warten auf Dateien handelt, die ein anderer Prozess erstellt, dann gibt's unter Umständen die Gefahr, dass die Datei zwar schon existiert, aber der andere Prozess noch beim schreiben ist, Du ihn in der Leseschleife "überholst" und damit eine nicht vollständige Datei verarbeitest ohne es zu merken.

Edit: Startargument von `count()` angepasst.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Er soll aber eben nicht mit der nächsten Nummer fortfahren, sondern die gleiche noch einmal versuchen.

Code: Alles auswählen

import sys

def tail_recursion_with_stack_inspection(g):
    '''
    Version of tail_recursion decorator using stack-frame inspection.    
    '''
    loc_vars ={"in_loop":False,"cnt":0}
    
    def result(*args, **kwd):
        if not loc_vars["in_loop"]:
            loc_vars["in_loop"] = True
            while 1:            
                tc = g(*args,**kwd)
                try:                    
                    qual, args, kwd = tc
                    if qual == 'continue':
                        continue
                except TypeError:                    
                    loc_vars["in_loop"] = False
                    return tc                                    
        else:
            f = sys._getframe()
            if f.f_back and f.f_back.f_back and \
                  f.f_back.f_back.f_code == f.f_code:
                return ('continue',args, kwd)
            return g(*args,**kwd)
    return result

def file_gen(count=0)
    @tail_recursion_with_stack_inspection
    def gen():
        try:
            path = FILE_TEMPLATE % count
            return open (path, 'r')
        except IOError:
            sleep(300)
            return gen()
    while True:
        count += 1
        yield gen()
:P

Oder aber:

Code: Alles auswählen

def file_gen()
    def gen():
        while True
            try:
                path = FILE_TEMPLATE % count
                return open (path, 'r')
            except IOError:
                sleep(300)
                continue
    while True:
        count += 1
        yield gen()
BlackJack

Das mit der Nummer ist in der ersten Beschreibung nicht so klar gewesen und in der ersten Lösung auch anders.

Naja, noch'n Versuch, weil das `retry_open()` ja wiederverwendbar ist:

Code: Alles auswählen

from itertools import count
from time import sleep

FILENAME_TEMPLATE = r'C:\text%s.txt'

retry_open(filename, mode, wait_time=300, max_retry=None):
    for retry in count(1):
        try:
            return open(filename, mode)
        except IOError:
            if max_retry and retry >= max_retry:
                raise
            else:
                sleep(wait_time)

def main():
    for lines in (retry_open(FILENAME_TEMPLATE % n) for n in count(1)):
        print '*** Begin reading file %s ***' % lines.name
        for line in lines:
            pass
        lines.close()
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Das mit der retry_open() funktion sieht gut aus.
Ich habe damit mal herum probiert, aber ich bekomme immer Syntaxfehler.

retry_open(filename, mode, wait_time=300, max_retry='None'):
SyntaxError: invalid syntax

Kannst du mir sagen wo ich dazu Infos finde? Zu dem retry_open
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

nordlocke hat geschrieben:Das mit der retry_open() funktion sieht gut aus.
Ich habe damit mal herum probiert, aber ich bekomme immer Syntaxfehler.
Da gehört ja auch noch ein ``def`` davor, weil es eben ``retry_open`` implementiert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Danke, ich sollte mir noch mal Funktionen unter Python durchlesen.
BlackJack

Ups :oops:

@nordlocke: Ich habe den Typ `None` für `max_retry` verwendet und keine Zeichenkette mit dem Inhalt 'None'. Das sind zwei unterschiedliche Dinge.
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Das ist mir schon aufgefallen, dachte du hättest einfach die '' vergessen und das ignoriert.

Wozu machst du genau die for schleife mit den retrys?
um eine Endlosschleife nicht zu bekommen?

Gibt es eigentlich die Möglichkeit zu sehen ob die Textdatei noch benutzt wird?
Ein anderes Programm legt ja die Dateien an und schreibt sie voll.
Momentan ist ja der stand das ich schaue ist die Datei schon da oder nicht.
Es kann ja aber auch sein, das die Datei schon da ist, aber noch ab voll schreiben ist. Kann man das auch abfangen?
BlackJack

@nordlocke: Das `max_retry` kann man auf die maximale Zahl der Wiederholungen setzen, bevor der `IOError` an den Aufrufer der Funktion weiter gegeben wird. Wenn `max_retry` ein "falscher" Wert ist, also zum Beispiel `None`, dann wird endlos wiederholt. Nicht ganz, weil `itertools.count()` "nur" `sys.maxint` Zahlen liefert, aber das sind bei 5 Minuten warten zwischen den Versuchen selbst auf einem 32-Bit-System etwas mehr als 20000 Jahre. Was man schon irgendwie als "endlos" bezeichnen kann. ;-)

Einen zuverlässigen, portablen Weg um zu erkennen, ob die Datei noch nicht fertig geschrieben wurde, kenne ich nicht. Wenn Du das schreibende Programm beeinflussen kannst, solltest Du erst in eine temporäre Datei schreiben, und diese wenn sie fertig ist umbenennen. Damit erscheinen die Daten für jemanden, der auf diese Datei wartet "auf einen Schlag".
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

BlackJack hat geschrieben:@nordlocke: Das `max_retry` kann man auf die maximale Zahl der Wiederholungen setzen, bevor der `IOError` an den Aufrufer der Funktion weiter gegeben wird. Wenn `max_retry` ein "falscher" Wert ist, also zum Beispiel `None`, dann wird endlos wiederholt. Nicht ganz, weil `itertools.count()` "nur" `sys.maxint` Zahlen liefert, aber das sind bei 5 Minuten warten zwischen den Versuchen selbst auf einem 32-Bit-System etwas mehr als 20000 Jahre. Was man schon irgendwie als "endlos" bezeichnen kann. ;-)
Ach. Aber bei einer Endlosrekursion meckern...das sind auch einige tausend Tage.
BlackJack

Das kommt darauf an wie oft so ein IOError vorkommt. Wenn der `IOError` permanent kommt sind das bloss ca. 3½ Tage.

Man sollte sich diese rekursiven "Schleifen" besser gar nicht erst angewöhnen, wenn bei 1000 Aufrufen schon Schluss ist. Diese Grenze trifft man dann unter Umständen recht schnell.
nordlocke
User
Beiträge: 13
Registriert: Freitag 8. Februar 2008, 10:19
Kontaktdaten:

Das ist ne menge Zeit :)

Ich habe auch nichts spezielles zur Datei gefunden, weiß auch gar nicht ob Windows das erkennt, leider läuft das Programm nämlich auf einer Windowskiste, daher habe lasse ich nun in eine Temporäredatei schreiben und wenn das fertig ist speichere ich es erst richtig weg.

Danke für die ganzen Tips und ein schönes Wochenende.
Antworten