Seite 1 von 1

In File schreiben schlauer gestalten

Verfasst: Mittwoch 8. September 2010, 14:36
von mzh
Hallo zusammen
Ich stehe öfters vor der Aufgabe, ein File einzulesen und einen Teil davon weiter zuverarbeiten, bspw. Koordinaten von Atomen in einem Protein. Diese Koordinaten stehen auf einer Zeile zusammen mit vielen anderen (nicht relevanten) Werten:

Code: Alles auswählen

ATOM    938 1HB  ALAAI  60      46.891   5.996  35.695  1.00  0.00      PROT  938
ATOM    939 2HB  ALAAI  60      45.176   5.623  35.701  1.00  0.00      PROT  939
ATOM    940 3HB  ALAAI  60      45.856   6.609  36.958  1.00  0.00      PROT  940
ATOM    941  HT  ILEAI  61      48.011   7.894  34.251  1.00  0.00      PROT  941
ATOM    942  HA  ILEAI  61      49.062   9.637  36.193  1.00  0.00      PROT  942
ATOM    943  HB  ILEAI  61      49.967   8.946  33.414  1.00  0.00      PROT  943
ATOM    944 1HG1 ILEAI  61      49.961   7.087  34.900  1.00  0.00      PROT  944
ATOM    945 2HG1 ILEAI  61      50.721   8.089  36.145  1.00  0.00      PROT  945
ATOM    946 1HG2 ILEAI  61      51.407  10.558  35.429  1.00  0.00      PROT  946
ATOM    947 2HG2 ILEAI  61      50.777  11.119  33.889  1.00  0.00      PROT  947
Mit Python kann man ja wunderbar über die Zeilen in einem File iterieren, die Zeilen splitten und dann die entsprechenden Elemente der gesplitteten Zeile in ein Zielfile rüberschreiben:

Code: Alles auswählen

 file = open('file.dat', 'w')
 file.write('')
 file.close()
 file = open('file.dat', 'w')
 resn_map = {}
 
 
 def getLine():
     data = open(arg, 'r')
     value = data.readlines()
 
     for line in enumerate(value):
         if line[1].split()[0] == 'ATOM' or 'HETATM':
 
             #            first relevant value    coordinates
             file.write(line[1][23:26] + ' ' + line[1][32:54] + '\n')
file.close()
Ich überschreibe das Zielfile hier jedesmal, damit es nicht bei jedem Start des Skripts weiter wächst. Gibt es dazu eine schlauere Lösung, als die Zeilen am Anfang des Codebeispiels?

Re: In File schreiben schlauer gestalten

Verfasst: Mittwoch 8. September 2010, 14:39
von snafu
Die Datei wird doch schon durch den Modus `w` überschrieben. Da wird nichts angehangen. Zumal ja dann auch der leere String angehangen werden müsste, wenn du mal drüber nachdenkst. ;)

Zudem hast du das Iterieren ja schon erwähnt. Du kannst in Python direkt über das Dateiobjekt iterieren und sparst dir damit das Lesen der gesamten Datei in den Speicher. Konkret also: `for line in data` anstatt `for line in value`. Auch die Verwendung von `enumerate()` ist reichlich sinnlos, wenn du überhaupt keine Durchnummerierung brauchst.

Auch würde ich an deiner Stelle, so wie du es beim Testen auf `ATOM` ja auch schon machst, hier auf den von `split()` erzeugten Spalten arbeiten anstatt auf den Zeichen, wenn du das Ergebnis abspeicherst. Sauberer wäre es wohl, das ganze Prozedere des Parsens in eine eigene Funktion auszulagern. Diese nimmt dann meinetwegen ein iterierbares Objekt an (was ja wie schon erwähnt z.B. etwas vom Typ `file()` sein kann) und gibt das Ergebnis zeilenweise mittels `yield` aus. Aber das ist vielleicht momentan noch etwas zuviel des Guten... ;)

Re: In File schreiben schlauer gestalten

Verfasst: Mittwoch 8. September 2010, 14:52
von mzh
Ich kann split hier nicht einsetzen, weil es nicht garantiert ist, dass ein Whitespace zwischen den Elementen steht, dh. die 'Elemente' könnten (in diesem unglaublich alten Dateiformat) direkt aneinander stehen, und da würde split() versagen.
Vielen Dank noch für die weiteren Ausführungen, die werde ich mir dann noch genauer anschauen.

Re: In File schreiben schlauer gestalten

Verfasst: Mittwoch 8. September 2010, 15:33
von gkuhl
@mzh: Du solltest versuchen "pythonischeren" Code zu schreiben, da dieser einfach schöner zu lesen ist. Wenn das Dateiformat fix ist, würde ich direkt mit Slicing zugreifen, solange die Zeile dadurch nicht zu lang wird.

Hier mal als Beispiel (ungetestet), wie ich es lösen würde:

Code: Alles auswählen

data = list()

with open(in_fname, 'r') as in_file:
    for line in in_file:
        if line.startswith('bla') or line.startswith('blubb'):
            x,y = line[23:26], line[42:55]
            data.append((x,y))

with open(out_fname, 'w') as out_file:
    for x,y in data:
        line = '{0:2d}{1:5.1f}\n'.format(x,y)
        outfile.write(line)
Grüße
Gerrit