In File schreiben schlauer gestalten

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
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

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?
[url=http://www.proandkon.com]proandkon.com[/url]
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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... ;)
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

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.
[url=http://www.proandkon.com]proandkon.com[/url]
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

@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
Antworten