misterunknown: Python - Syntax error bei open()

Moin,

ich schreibe gerade ein Python-Skript (was ich vorher noch nie gemacht habe) und hangle mich syntax-technisch an diesem Tutorial entlang.

Ich will für den Anfang ein Skript, welches ich ursprünglich in PHP geschrieben habe ein Python-Äquivalent schaffen. Die Zeile bei der ich nicht weiterkomme ist folgende:

//PHP  
$i=0;  
$data = array();  
while(!feof($handle)) {  
   $buffer = fgets($handle);  
   if(isset($buffer) && $buffer != "") {  
      $datarr = explode(";", $buffer);  
      $data[$i]['ea'] = trim(str_replace(".","",$datarr[0]));  
      $data[$i]['okz'] = trim(str_replace(".","",$datarr[1]));  
      $data[$i]['k'] = trim(str_replace(".","",$datarr[2]));  
      $data[$i]['v'] = trim(str_replace(".","",$datarr[3]));  
      $i++;  
   }  
}
#Python  
i = 0  
data = []  
for line in handle:  
   if line != "":  
      data[i]['ea'] = line.split(";")[0].replace(".", "").strip()  
      data[i]['okz'] = line.split(";")[1].replace(".", "").strip()  
      data[i]['k'] = line.split(";")[2].replace(".", "").strip()  
      data[i]['v'] = line.split(";")[3].replace(".", "").strip()  
      i = i+1

Das Array data initialisiere ich in PHP per array(). Wie sieht es bei Python aus? Mit obigem Code bekomme ich folgenden Fehler:

  File "aufgabeChristia.py", line 12, in <module>  
    data[i]['ea'] = line.split(";")[0].replace(".", "").strip()  
IndexError: list index out of range

Wie müsste die Syntax aussehen, wenn ich ein Array haben will, was wie das aussieht, welches der PHP-Code erzeugt?

Grüße Marco

  1. Moin,

    Die Überschrift gehört natürlich zu einem anderen Problem, welches ich zwischenzeitlich gelöst hatte -.-

    Grüße Marco

  2. Tach!

    Auch du hast kein mehrdimensionales Array im eigentlichen Sinne vorliegen. Verdeutliche dir stattdessen die wirkliche Struktur (notfalls mit print_r() oder var_dump()).

    $data = array();

    $data ist nun ein leeres PHP-Array, was später alle möglichen Strukturen aufnehmen kann. (Siehe einleitender Absatz zu Arrays.)

    $data[$i]['ea'] = trim(str_replace(".","",$datarr[0]));

    Nun legst du mit selbst vergebenem Schlüssel etwas in dieses Array. Die Schlüssel sind numerisch und fortlaufend, also hast du das, was man eine Liste nennt. Das Selbst-Verwalten von $i ist aber gar nicht notwendig, wenn du die als Wert in jedem Listeneintrag abzulegende Struktur zuerst erstellst und sie dann komplett $data[] = zuweist. Dann könntest du auch viel besser sehen, dass du da zunächst ein Array (in diesem Fall ein Dictionary) anlegst. Das explizite Initialisieren dieses Arrays hast du aber unterlassen. Stattdessen vertraust du PHPs Mechanismus, alles anzulegen, was du schreibend verwendest. Diesen Mechanismus verwendest du auch beim erstmaligen Ansprechen von $data[$i].

    data = []
          data[i]['ea'] = line.split(";")[0].replace(".", "").strip()

    Der PHP-Weg funktioniert aber so nicht in Python (zumindest nicht für Listen, wohl aber für Dictionarys). Die Initialisierung einer Liste ist richtig. Aber das Anfügen von Elementen geht nicht durch einfaches Verwenden von (noch) nicht vorhandenen Index-Werten, sondern mit einer Methode oder einem List Operator. ("Dive Into Python" ist auch ein nicht zu verachtendes Python-Buch. Für dein Problem: das Lists-Kapitel.)

    IndexError: list index out of range

    Du greifst auf einen Index zu, der nicht im Array vorhanden ist. - Nebenbei: Anders als bei PHP kann eine Python-Liste auch keine Lücken im Index aufweisen, weil die Index-Werte echte Postionsnummern sind und nicht einfach nur ein Key mit numerischem Inhalt.

    data[i]['ea'] = line.split(";")[0].replace(".", "").strip()
          data[i]['okz'] = line.split(";")[1].replace(".", "").strip()
          data[i]['k'] = line.split(";")[2].replace(".", "").strip()
          data[i]['v'] = line.split(";")[3].replace(".", "").strip()

    Ich würde hier nur einmal splitten sowie die Punkte vorher entfernen und nicht jedes Mal extra (es sei denn, du hast Felder, in denen sie drin bleiben sollen).

    dedlfix.

    1. Moin,

      Der PHP-Weg funktioniert aber so nicht in Python (zumindest nicht für Listen, wohl aber für Dictionarys).

      Danke für den Hinweis. Dictionarys hatte ich bei meinem Blitz-Einleitungskurs wahrscheinlich übersehen.

      ("Dive Into Python" ist auch ein nicht zu verachtendes Python-Buch. Für dein Problem: das Lists-Kapitel.)

      Danke für den Link.

      Du greifst auf einen Index zu, der nicht im Array vorhanden ist. - Nebenbei: Anders als bei PHP kann eine Python-Liste auch keine Lücken im Index aufweisen, weil die Index-Werte echte Postionsnummern sind und nicht einfach nur ein Key mit numerischem Inhalt.

      Das dürfe dann eine Rolle spielen, wenn man ein Element aus der Liste löscht, richtig?

      Ich würde hier nur einmal splitten sowie die Punkte vorher entfernen und nicht jedes Mal extra (es sei denn, du hast Felder, in denen sie drin bleiben sollen).

      Hm. Ich dachte, dass es speicherschonender ist, wenn man diese Liste nicht in einer Variable speichert. Aber da leidet wohl die Performance.

      Ich habe das Skrip jetzt bis bis zu dieser Stelle fertig (data enthält alle meine Werte, wie gewünscht). Funktionieren tuts also, aber findest du den Code sinnvoll? Oder gibts da noch Optimierungsspielraum:

      import sys;  
      try:  
      	handle = open("input.txt")  
      except:  
      	sys.exit('No input file. Aborting...')  
        
      data = []  
      for line in handle:  
      	if line.strip() != "":  
      		curline = line.replace(".", "").split(";");  
      		curset = { 'ea': curline[0].strip(),  
      		'okz': curline[1].strip(),  
      		'k': int(curline[2].strip()),  
      		'v': int(curline[3].strip()) }  
      		data.append(curset);  
      for item in data  
      	print(item)
      

      (die strip()-Funktionen sind aufgrund der etwas kruden Export-Funktion des Oracle SQL Developers nötig, jedenfalls kann ich mir anders nicht die Struktur der TXT erklären, die ich bekommen habe)

      Eine Frage noch: Die Integer-Parse-Funktion wirft in meinem Fall keinen Error, da die Werte alle umgeformt werden können. Aber generell: gibt es eine Art ternären Operator mit dem man direkt vor der Zuweisung prüfen kann, ob int() überhaupt möglich ist und andernfalls 0 übergeben? Ich habe nichts gefunden was mir dahingehend hilft. Ich habe nur dieses Statement gefunden, welches aber trotzdem zum Abbruch des Programms führt, wenn die int()-Funktion eine Exception wirft.

      Grüße Marco

      1. Tach!

        Funktionieren tuts also, aber findest du den Code sinnvoll? Oder gibts da noch Optimierungsspielraum:
            if line.strip() != "":

        Den Vergleich mit dem Leerstring kann man weglassen. Im booleschen Kontext liefert ein Leerstring false, alle andere true.

          curset = { 'ea': curline[0].strip(),  
          'okz': curline[1].strip(),  
          'k': int(curline[2].strip()),  
          'v': int(curline[3].strip()) }  
          data.append(curset);  
        

        curset ist ersetzbar, indem du die Dictionary-Erzeugung als Parameter von data.append() notierst. Aber du kannst das auch ruhig so lassen, die eine Variable macht das Kraut nicht fett. Ich würde das jedoch optisch anders notieren.

        curset = {
            'ea': curline[0].strip(),
            'okz': curline[1].strip(),
            'k': int(curline[2].strip()),
            'v': int(curline[3].strip()),
          }

        Beachte auch das letzte Komma. Das fügt wie in PHP kein (leeres) Element mehr an, aber beim Umsortieren und Erweitern muss man sich nicht mehr darum kümmern, wo nun noch Kommas zu korrigieren sind.

        Eine Frage noch: Die Integer-Parse-Funktion wirft in meinem Fall keinen Error, da die Werte alle umgeformt werden können. Aber generell: gibt es eine Art ternären Operator mit dem man direkt vor der Zuweisung prüfen kann, ob int() überhaupt möglich ist und andernfalls 0 übergeben? Ich habe nichts gefunden was mir dahingehend hilft.

        Ich suche in solchen Fälle nach "python" und dem Namen einer PHP-Funktion mit gleichem Umfang, in dem Fall "is_numeric" => str.isdigit()
        Andere Sprachen gehen natürlich auch, wie C#'s tryparse.

        Ich habe nur dieses Statement gefunden, welches aber trotzdem zum Abbruch des Programms führt, wenn die int()-Funktion eine Exception wirft.

        Exceptions kann man auch nur in einem try-except-Statement fangen.

        dedlfix.

        1. Moin,

          Den Vergleich mit dem Leerstring kann man weglassen. Im booleschen Kontext liefert ein Leerstring false, alle andere true.

          Aha. Ich hab den Vergleich entfernt.

          Beachte auch das letzte Komma. Das fügt wie in PHP kein (leeres) Element mehr an, aber beim Umsortieren und Erweitern muss man sich nicht mehr darum kümmern, wo nun noch Kommas zu korrigieren sind.

          Das wusste ich nicht. Weder bei PHP noch bei Python. Ich hab das gewohnheitsmäßig immer so gemacht, weil ich nebenbei viel mit SQL mache und selbiges regt sich über ein Komma zuviel hinter dem letzten Element auf...

          Ich suche in solchen Fälle nach "python" und dem Namen einer PHP-Funktion mit gleichem Umfang, in dem Fall "is_numeric" => str.isdigit()
          Andere Sprachen gehen natürlich auch, wie C#'s tryparse.

          Stimmt. Ich hatte auch schon php2python.com gefunden, habe aber nicht an is_numeric() gedacht, sondern hing an der Idee fest die Exception durch ein ?-Statement aufzufangen.
          Ich habs jetzt so gelöst:
          'k': int(curline[2].strip()) if curline[2].strip().isdigit() else 0,

          Danke für die Hinweise :)

          Grüße Marco