Ich möchte ein Textfile mit folgendem oder ähnlichen Inhalt einlesen,
und als Variablen zum rechnen verwenden:
Textfile "Vardat.txt" :
# Floats und Integers
a = 1.271
b = 8
# texte
c = 'text'
Kein Problem mit
fh = open('Vardat.txt')
for line in fh:
exec(line)
print('a = ',a)
print('b = ',b)
print('c = ',c)
print('d = ',3+a*b)
Wie erhofft erhalte ich Variablen, mit denen ich arbeiten bzw. rechnen kann:
a = 1.271
b = 8
c = text
d = 13.168
A B E R : mit folgendem Skript geht es nicht
from tkinter import *
from tkinter import filedialog
def leave():
ws.destroy()
ws.quit()
def readFileAndConvert():
tf = filedialog.askopenfilename(title="Open Text file", filetypes=(("Text Files", "*.txt"),))
tf = open(tf, 'r')
for line in tf:
print(line)
exec(line)
tf.close()
print('a = ',a)
print('b = ',b)
print('c = ',c)
print('d = ',3+a*b)
ws = Tk()
ws.title("loading txt-file")
ws.geometry("300x200")
commandButton = Button(ws, text="Open File", command=readFileAndConvert)
commandButton.place(x=20, y=50, width=80, height=20)
leaveButton = Button(ws, text='Leave !', command=leave)
leaveButton.place(x=20, y=150, width=80, height=20)
ws.mainloop()
Hier die Antwort:
# Floats und Integers
a = 1.271
b = 8
# texte
c = 'text'
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
return self.func(*args)
File "/home/ich/PYTHON_PROGRAMME/LOADFILE/DialogLoadFile.py", line 26, in readFileAndConvert
print('a = ',a)
NameError: name 'a' is not defined
Gut, einlesen klappt, aber es werden keine Variablen erzeugt.
Seit Wochen suche ich im ganzen Internet herum, aber ich bekomme immer nur Antworten, wie
ich solle mit json, pandas, pickles, csv, strip usw. arbeiten, das ist mir zu viel Affentheater.
Mit Matlab ( eval) und Scilab ( exec) get es sehr einfach. Mit Python, der Sprache der Zukunft
muß man Zaubertricks ohne Ende ausprobieren und kommt doch nicht zum Ziel.
Vielleicht weiß im Forum jemand weiter ?
Textfile einlesen und Variablen zum rechnen verwenden
- __blackjack__
- User
- Beiträge: 13103
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@ulRa: Vergiss bitte gleich mal wieder `eval` und `exec`. In den Augen von Programmierern sind *das* nämlich die Zaubertricks. Wenn Dir eine saubere Lösung statt solcher Hacks zu viel Affentheater sind, dann bleib bei Matlab und/oder Scilab.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hallo ulRa,
dein Code funktioniert nicht, da exec() innerhalb der Funktion ausgeführt wird. Bei tkinter kannst du das aber nicht vermeiden.
Außerdem we __blackjack__ schon sagt, sollte man exec und eval nicht verwenden, da die Zeile dann mit allen gefährlichen Nebeneffekten ausgeführt wird.
Wenn ich richtig verstanden habe, was du machen willst, kannst du so etwas ähnliches machen:
Ausgabe:
a
10
a = 10
dein Code funktioniert nicht, da exec() innerhalb der Funktion ausgeführt wird. Bei tkinter kannst du das aber nicht vermeiden.
Außerdem we __blackjack__ schon sagt, sollte man exec und eval nicht verwenden, da die Zeile dann mit allen gefährlichen Nebeneffekten ausgeführt wird.
Wenn ich richtig verstanden habe, was du machen willst, kannst du so etwas ähnliches machen:
Code: Alles auswählen
line = "a = 10"
name, value = line.replace(" ", "").split("=")
print(name)
print(value)
print(f"{name} = {value}")
a
10
a = 10
Hallo rogerb,
vielen Dank für Deinen Tip.
So bekomme ich aber noch keine Variable. Ich erweitere mal Deinen Vorschlag:
line = "a = 10"
name, value = line.replace(" ", "").split("=")
print('name =',name)
print(f"{name} = {value}")
a=(float(value))
print('a =',a)
und erhalte
name = a
a = 10
a = 10.0
Jetzt habe ich eine Variable.
Das heißt also : ich kann die Variable durch einen eingelesenen string-Ausdruck nicht erzeugen,
sondern sie muß schon existieren und ich muß ihr irgendwie den rechten Teil des gesplitteten
Ausdrucks als float zuordnen. Wenn es denn ein float sein soll und kein integer oder string.
Und es zwingt mich, mir für die auskommentierten Zeilen im Datenfile noch eine Sonderbehandlung
zu erfinden. Schöne Aussichten.
Der Hintergrund ist: Die Textdatei soll etwa 80 Zeilen nach dem Muster name = value
bzw. name = string und einige Kommentarzeilen enthalten. Die Variablen sind Parameter für Designberechnungen.
Eine Muster-GUI mit tkinter, die Berechnungen und die graphische Darstellung eines etwas komplexen
Gebildes mittels matplotlib funktionieren bereits gut. Nun will ich die Parameter auch speichern und bei Bedarf
wieder aufrufen. Allerdings möchte ich die Textdatei auch mittels Texteditor sehr einfach überblicken und evtl. editieren
können.
vielen Dank für Deinen Tip.
So bekomme ich aber noch keine Variable. Ich erweitere mal Deinen Vorschlag:
line = "a = 10"
name, value = line.replace(" ", "").split("=")
print('name =',name)
print(f"{name} = {value}")
a=(float(value))
print('a =',a)
und erhalte
name = a
a = 10
a = 10.0
Jetzt habe ich eine Variable.
Das heißt also : ich kann die Variable durch einen eingelesenen string-Ausdruck nicht erzeugen,
sondern sie muß schon existieren und ich muß ihr irgendwie den rechten Teil des gesplitteten
Ausdrucks als float zuordnen. Wenn es denn ein float sein soll und kein integer oder string.
Und es zwingt mich, mir für die auskommentierten Zeilen im Datenfile noch eine Sonderbehandlung
zu erfinden. Schöne Aussichten.
Der Hintergrund ist: Die Textdatei soll etwa 80 Zeilen nach dem Muster name = value
bzw. name = string und einige Kommentarzeilen enthalten. Die Variablen sind Parameter für Designberechnungen.
Eine Muster-GUI mit tkinter, die Berechnungen und die graphische Darstellung eines etwas komplexen
Gebildes mittels matplotlib funktionieren bereits gut. Nun will ich die Parameter auch speichern und bei Bedarf
wieder aufrufen. Allerdings möchte ich die Textdatei auch mittels Texteditor sehr einfach überblicken und evtl. editieren
können.
- __blackjack__
- User
- Beiträge: 13103
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@rogerb: Das Ersetzen der Leerzeichen ist keine gute Idee. Da wären dann am Ende "foo bar = 42" und "foobar=42" gleich.
@ulRa: Dann nimm JSON, YAML, CSV, TOML, …
Ist ja nicht so als gäbe es für so etwas keine etablierten Formate und Module.
@ulRa: Dann nimm JSON, YAML, CSV, TOML, …
Ist ja nicht so als gäbe es für so etwas keine etablierten Formate und Module.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
So zusammen,
jetzt hab' ich's. Der entscheidende Tip war : name, value = line.replace(" ", "").split("=").
Die Textdatei sieht jetzt so aus :
# = Floats und Integers
a = 1.271
b = 8
# = texte
c ='text'
also Gleichheitszeichen auch in den Kommentarzeilen,
damit deren Fehlen nicht zu Beanstandungen führt. (Vielleicht geht's auch ohne.
Und das Skript:
from tkinter import *
from tkinter import filedialog
def leave():
ws.destroy()
ws.quit()
def readFileAndConvert():
fh = filedialog.askopenfilename(title="Open Text file", filetypes=(("Text Files", "*.txt"),))
fh = open(fh, 'r')
for line in fh:
name, value = line.replace(" ", "").split("=")
if name=='a':
a=(float(value))
elif name=='b':
b=(float(value))
elif name=='c':
c=(str(value))
fh.close()
return(a,b,c)
def useVars():
(a,b,c) = readFileAndConvert()
print('a = ',a)
print('b = ',b)
print('c = ',c)
print('d = ',3+a*b)
ws = Tk()
ws.title("loading txt-file")
ws.geometry("300x200")
commandButton = Button(ws, text="Open File", command=useVars)
commandButton.place(x=20, y=50, width=80, height=20)
leaveButton = Button(ws, text='Leave !', command=leave)
leaveButton.place(x=20, y=150, width=80, height=20)
ws.mainloop()
macht genau, was ich will. Es geht also doch ohne JSON, YAML, CSV, TOML.
Danke nochmal für den "Beistand"
jetzt hab' ich's. Der entscheidende Tip war : name, value = line.replace(" ", "").split("=").
Die Textdatei sieht jetzt so aus :
# = Floats und Integers
a = 1.271
b = 8
# = texte
c ='text'
also Gleichheitszeichen auch in den Kommentarzeilen,
damit deren Fehlen nicht zu Beanstandungen führt. (Vielleicht geht's auch ohne.
Und das Skript:
from tkinter import *
from tkinter import filedialog
def leave():
ws.destroy()
ws.quit()
def readFileAndConvert():
fh = filedialog.askopenfilename(title="Open Text file", filetypes=(("Text Files", "*.txt"),))
fh = open(fh, 'r')
for line in fh:
name, value = line.replace(" ", "").split("=")
if name=='a':
a=(float(value))
elif name=='b':
b=(float(value))
elif name=='c':
c=(str(value))
fh.close()
return(a,b,c)
def useVars():
(a,b,c) = readFileAndConvert()
print('a = ',a)
print('b = ',b)
print('c = ',c)
print('d = ',3+a*b)
ws = Tk()
ws.title("loading txt-file")
ws.geometry("300x200")
commandButton = Button(ws, text="Open File", command=useVars)
commandButton.place(x=20, y=50, width=80, height=20)
leaveButton = Button(ws, text='Leave !', command=leave)
leaveButton.place(x=20, y=150, width=80, height=20)
ws.mainloop()
macht genau, was ich will. Es geht also doch ohne JSON, YAML, CSV, TOML.
Danke nochmal für den "Beistand"
Klar, gehen tut das schon. Die Frage ist halt, wie . Jede Variable einzeln aus der Textdatei herauszuparsen und dann manuell an einen hard-gecodeten Namen zu binden, ist nicht besonders flexibel, nicht besonders robust und skaliert sehr schlecht; das muss dir doch auffallen.
Genau so etwas versucht man beim Programmieren jedenfalls eigentlich zu vermeiden. Und dabei hätten dir zum Beispiel die genannten Formate geholfen, für die es Parser gibt, die das in ordentlich erledigen.
*-Importe sollte man nicht benutzen, weil dadurch keine Zuordnung von Namen zu Modulen mehr möglich ist.
Globale Variablen soll man nicht benutzen, weil dann eine Funktion keine in sich geschlossen Einheit ist, was Fehlerursache und -suche sehr komplex macht.
Variablennamen und Funktionen schreibt man nach Konvention komplett klein.
Benutze keine kryptischen Abkürzungen, was soll `ws` bedeuten?
`leave` ist unnötig, da wenn das Hauptfenster geschlossen wird, automatisch auch `quit` ausgeführt wird.
`place` sollte man nicht verwenden, weil Änderungen an der GUI dadurch sehr kompliziert werden und es nur auf einem System mit einer Bildschirmauflösung "gut" aussieht, bei anderen Systemen könnte das Fenster aber unbenutzbar sein, weil Dinge übereinander liegen, oder außerhalb des Fensters.
Dateien öffnet man mit Hilfe des with-Statements, damit garantiert ist, dass die Datei auch wieder geschlossen wird.
Für Deinen Parser würde man erst prüfen, ob es ein Kommentarzeile ist und diese dann ignorieren. Normalerweise werden auch Leerzeilen ignoriert.
Statt `split` nimmt man in diesem Fall `partition`. Das funktioniert auch, wenn kein = in einer Zeile vorkommt.
Statt einzeln Variablen zu definieren, würde man eine passende Datenstruktur verwenden, z.B. ein Wörterbuch.
In Deiner jetzigen Implementierung dürfen keine Leerzeilen vorkommen, a, b, oder c dürfen nicht fehlen, wenn a oder b fehlen, bekommst Du einen NameError, bei c wird einfach None zurückgegeben. c muß als letztes definiert werden.
Das sind alles keine schönen Eigenschaften für einen Parser, daher solltest Du etwas etabliertes nehmen, wo es schon fertige Module gibt. TOML kommt Deiner erfundenen Konfigurationssprache recht nahe.
Globale Variablen soll man nicht benutzen, weil dann eine Funktion keine in sich geschlossen Einheit ist, was Fehlerursache und -suche sehr komplex macht.
Variablennamen und Funktionen schreibt man nach Konvention komplett klein.
Benutze keine kryptischen Abkürzungen, was soll `ws` bedeuten?
`leave` ist unnötig, da wenn das Hauptfenster geschlossen wird, automatisch auch `quit` ausgeführt wird.
`place` sollte man nicht verwenden, weil Änderungen an der GUI dadurch sehr kompliziert werden und es nur auf einem System mit einer Bildschirmauflösung "gut" aussieht, bei anderen Systemen könnte das Fenster aber unbenutzbar sein, weil Dinge übereinander liegen, oder außerhalb des Fensters.
Dateien öffnet man mit Hilfe des with-Statements, damit garantiert ist, dass die Datei auch wieder geschlossen wird.
Für Deinen Parser würde man erst prüfen, ob es ein Kommentarzeile ist und diese dann ignorieren. Normalerweise werden auch Leerzeilen ignoriert.
Statt `split` nimmt man in diesem Fall `partition`. Das funktioniert auch, wenn kein = in einer Zeile vorkommt.
Statt einzeln Variablen zu definieren, würde man eine passende Datenstruktur verwenden, z.B. ein Wörterbuch.
In Deiner jetzigen Implementierung dürfen keine Leerzeilen vorkommen, a, b, oder c dürfen nicht fehlen, wenn a oder b fehlen, bekommst Du einen NameError, bei c wird einfach None zurückgegeben. c muß als letztes definiert werden.
Das sind alles keine schönen Eigenschaften für einen Parser, daher solltest Du etwas etabliertes nehmen, wo es schon fertige Module gibt. TOML kommt Deiner erfundenen Konfigurationssprache recht nahe.
Code: Alles auswählen
import tkinter as tk
from tkinter import filedialog
def read_vars():
filename = filedialog.askopenfilename(title="Open Text file", filetypes=(("Text Files", "*.txt"),))
result = {}
with open(filename, encoding="utf8") as lines:
for line in lines:
line = line.strip()
if not line or line.startswith('#'):
# ignore
pass
else:
name, equal_sign, value = line.partition("=")
if not equal_sign:
# was auch immer bei einer falschen Zeile passieren soll.
raise RuntimeError("error parsing line %r" % line)
result[name] = value
return result
def use_vars():
result = read_vars()
print('a = ', result['a'])
print('b = ', result['b'])
print('c = ', result['c'])
print('d = ', 3 + float(result['a']) * float(result['b']))
def main():
window = tk.Tk()
window.title("loading txt-file")
tk.Button(window, text="Open File", command=use_vars).pack()
tk.Button(window, text='Leave !', command=window.destroy).pack()
window.mainloop()
if __name__ == "__main__":
main()