Dynamische Variablendeklaration

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
pythonitas
User
Beiträge: 1
Registriert: Samstag 1. Oktober 2016, 21:06

Hallo alle zusammen,

ich habe mir mit Python3.4 und dem RaspPi3 eine Ofensteuerung gebaut.
Funktioniert auch alles, jedoch ist der Code teilweise unelegant und deswegen sehr lang, und das würde ich gern optimieren.

Funktionsbeschreibung
###################

In einer Textdatei habe ich ein Temperaturprofil hinterlegt nach folgendem Schema(sek=Sekunden, Temp=Soll-Temperatur):
Sek Temp
=========
010 035
020 054
030 072
040 109
usw.

Die Werte sind jeweils 3stellig und bei Bedarf um eine Null ergänzt, getrennt durch ein Leerzeichen.
Damit kann ich dann verschiedene Profile durch verschiedene Dateien einlesen.
Die Datei lese ich ein und speichere die Werte als Variable. Damit fahre ich dann eine Temperaturrampe ab.


Aktuelles Code-Schema
##################

Code: Alles auswählen

f=open("Datei")
zeilen=f.readlines()
# 1. Zeile auslesen
zeile1=zeilen[0]
zeit1=int(zeile1[0:3])
temp1=int(zeile1[4:7])
# 2. Zeile auslesen
zeile2=zeilen[1]
zeit2=int(zeile2[0:3])
temp2=int(zeile2[4:7])
# usw.
Zielcode
#######

Ich würde es gern nach folgendem Schema umsetzen, schaffe es aber nicht.

Code: Alles auswählen

f=open("Datei")
zeilen=f.readlines()
i=1
# Zeilen auslesen
while i<10:
  zeile(i)=zeilen[i-1]
  zeit(i)=int(zeile(i)[0:3])
  temp(i)=int(zeile(i)[4:7])
  i+=1
# usw.
Wie muss ich vorgehen, dass "zeile(i)" usw. richtig umgesetzt wird und dann per Inkrementierung der Reihe nach eingelesen wird?

Danke schonmal und einen schönen Abend.
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

Statt durchnummerierter Variablen nimmt man dafür eher eine geeignete Datenstruktur, etwa ein Dictionary oder eine Liste.

Hier mal ein Vorschlag, wie man das vielleicht manchen könnte

Code: Alles auswählen

#!/usr/bin/env python3
import argparse
import re

PATTERN = re.compile(r'(?P<second>\d{3})\s(?P<temperature>\d{3})')


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('file_name')
    args = parser.parse_args()
    times = dict()
    with open(args.file_name) as fh:
        for line in fh:
            result = re.match(PATTERN, line)
            if result:
                times[result.group('second')] = result.group('temperature')
    print(times)

if __name__ == '__main__':
    main()
(Doppelte Uhrzeiten werden zur Zeit überschrieben; je nach Ziel könnte sich z. B. ein defaultdict eignen)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@pythonitas: was Du suchst, ist eine Liste:

Code: Alles auswählen

zeiten = []
temperaturen = []
with open("Datei") as lines:
    for line in lines:
        zeit, temperatur = map(int, line.split())
        zeiten.append(zeit)
        temperaturen.append(temperatur)
print(zeiten[0], temperaturen[0])
Eine feste Anzahl an Stellen für Werte in einer Datei zu haben, ist unüblich. Wenn man ein Trennzeichen (hier Leerzeichen) hat, dann kann man die Zeilen ja einfach an diesem Zeichen aufspalten.
Statt zwei getrennter Listen will man die Werte pro Zeile enger beieinander haben, entweder mit Hilfe von namedtuplen:

Code: Alles auswählen

from collections import namedtuple
ZeitMitTemperatur = namedtuple("ZeitMitTemperatur", "zeit,temperatur")
temperaturen = []
with open("Datei") as lines:
    for line in lines:
        temperaturen.append(ZeitMitTemperatur(*map(int, line.split())))
print(temperaturen[0].zeit, temperaturen[0].temperatur)
oder gleich in einem numpy-Array:

Code: Alles auswählen

import numpy
temperaturen = numpy.genfromtxt("Datei", names=["zeit","temperatur"])
print(temperaturen[0]['zeit'], temperaturen[0]['temperatur'])
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Die RE-Keule für eine Angelegenheit, welche sich mit Zeichenkettenoperationen erledigen lassen?

Ungetestet:

Code: Alles auswählen

result = {int(s): int(t) for s, t in (line for line in islice(file, 1, None))}
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

bwbg hat geschrieben: Die RE-Keule für eine Angelegenheit, welche sich mit Zeichenkettenoperationen erledigen lassen?
Die konkrete Aufgabe lässt sich mit Zeichenkettenoperationen schnell lösen. Wenn das Muster allerdings doch komplexer wird, als zunächst angenommen, werden diese schnell unhandlich. Da das bei solchen Parsingaufgaben durchaus vorkommen kann, finde ich es angemessen, gleich reguläre Ausdrücke zu verwenden; der overhead, der bei dem kleinen Skript entsteht ist ja nicht so riesig.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@nezzcarth: ich sehe da eine Folge von durch Leerzeichen getrennte Zahlen und kein Muster der Form 3 Ziffern 1 Leerzeichen, 3 Ziffern und danach irgendetwas beliebiges. Eine natürliche Erweiterung solcher Daten ist dann nicht exakt 3 Ziffern, Kommazahlen, mehr als 2 Zahlen pro Zeile, etc. Da werden reguläre Ausdrücke beliebig komplex und schwer zu lesen.
BlackJack

@nezzcarth: Es verletzt auch das KISS-Prinzip und grenzt an YAGNI. Wenn die Daten dann tatsächlich anders aussehen, ist es leicht `re` statt `split()` zu verwenden. Wenn sie nicht anders aussehen hat man unnötig `re` verwendet. Es geht ja nicht nur um die Komplexität des Ausdrucks den Du da verwendest, sondern das jemand der es liest und dann schaut was `re` eigentlich ist/macht eher erschlagen wird von Informationen und komischer zusätzlicher Syntax, als wenn man einfach nur `str.split()` nachliest.

Edit: Mit einem ähnlichen Argument könnt man dann auch gleich `pyparsing` verwenden, weil das wie Sirius3 anmerkt auch mit regulären Ausdrücken schnell unübersichtlich werden kann, und man dann vielleicht lieber eine lesbarere Grammatik verwenden möchte. ;-)
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

Na gut, überzeugt -- vielleicht ;)

(Was mir vorschwebt, ist beispielsweise, dass man noch die Spaltennamen in Zeile 1 sowie Kommentare verarbeiten und Syntaxfehler abfangen wollen würde. Das ließe sich beispielsweise einheitlich über drei reguläre Ausdrücke lösen, die nacheinander geprüft werden. Im Prinzip landet man dann bei einer einheitlichen Programmstruktur, die relativ unabhängig von der konkreten Anzahl der Regeln ist. Oder würde man das eher nicht so machen? Aber ich sehe ein, dass, hier BlackJacks YAGNI-Einwand vielleicht auch greift.)
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Möglichst anfängerfreundlich ohne LC und ohne `map()`:

Code: Alles auswählen

def parse_data(filename):
    result = list()
    with open(filename) as infile:
        for line in infile:
            parts = line.split()
            sekunden = int(parts[0])
            temperatur = int(parts[1])
            result.append((sekunden, temperatur))
    return result

def print_data(data):
    for sekunden, temperatur in data:
        print(sekunden, temperatur)
Antworten