Array speichern nach mehrfachen Funktionsaufruf

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
felopy
User
Beiträge: 17
Registriert: Mittwoch 3. Juni 2015, 08:55

Hallo,
habe ein kleines Anfängerproblem. Ich will mit askopenfilename einen String in ein Array bzw. Liste speichern, dies aber mehrfach ausführen.
Allerdings resetet es jedesmal mein Array, wenn ich die Funktion wieder aufrufe.
Kann mir da mal bitte jemand helfen?

Code: Alles auswählen

 
 def array(self, liste):
    daten_in = []
    daten_in.append(liste)
    #print(structs_in)

  def einlesen(self):
    eingabe = askopenfilename()
    self.array(eingabe)
MfG
Felopy
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@felopy: was soll den die Funktion array machen? Bisher tut sie gar nichts, außer eine lokale Variable zu erzeugen und wieder zu verwerfen.
felopy
User
Beiträge: 17
Registriert: Mittwoch 3. Juni 2015, 08:55

sie soll nur das Array füllen und eben nicht jedesmal verwerfen.
Den Inhalt des Arrays will ich dann an andere Stelle nutzen.

Bsp.:
ich drück 3mal einen Button und jedesmal wähle ich eine andere Datei aus.
Ich hätte dann gerne ein Array mit den 3 ausgewählten Dateinamen
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@felopy: den Ausschnitt aus Deinem Programm, den Du gepostet hast, macht so überhaupt keinen Sinn. Wenn Du eine Liste mit "[]" erzeugst und dann ein Element anhängst, dann ist in dieser Liste ein Element, was aber wie gesagt egal ist, weil die Liste sofort wieder verworfen wird. Zeig ein lauffähiges Programm, das Dein Problem illustriert, beschreibe Dein erwartetes Verhalten und das tatsächliche Verhalten des Programms.
felopy
User
Beiträge: 17
Registriert: Mittwoch 3. Juni 2015, 08:55

wie kann ich denn verhindern, dass die Liste verworfen wird?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@felopy: Dann musst Du Dir das Listenobjekt irgend wo *merken*! Konkreter kann man das ohne mehr Infos zum Kontext nicht beantworten...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

felopy hat geschrieben:Bsp.:
ich drück 3mal einen Button und jedesmal wähle ich eine andere Datei aus.
Ich hätte dann gerne ein Array mit den 3 ausgewählten Dateinamen
Dazu lautet der Pseudocode dann normalerweise:

Code: Alles auswählen

dateinamen = []
while not eingabe_abgeschlossen:
    dateinamen.append(erfrage_dateiname())
verarbeite(dateinamen)
Was ich damit sagen will: Funktionen fummeln nicht an halb-fertigen Listen herum, sondern Listen werden entweder in einer Schleife nach und nach mit Funktionsrückgaben befüllt (wie im gezeigten Pseudocode) oder die Funktionen kümmern sich um die Erzeugung einer vollständigen Liste und geben diese vollständige Liste als Rückgabewert aus (entspräche Zeile 1-3 bei mir + `return` anstatt `verarbeite` in Zeile 4).

Du solltest deinen Code also so umbauen, dass er diesen Anforderungen entspricht. Und im Falle einer Schleife muss es dann eben eine definierte Abbruchbedingung geben, d.h. der Punkt, an dem die Liste nicht weiter befüllt wird, sollte feststehen (etwa: solange der Anwender nicht "Fertig" geklickt hat, werden weitere Eingaben erfragt).
felopy
User
Beiträge: 17
Registriert: Mittwoch 3. Juni 2015, 08:55

soweit verstehe ich das, allerdings ist das mit der Abbruchbedingung verwirrend.. ich habe ja keine abfrage per "input("nochmal?")" sondern mache das über eine Button in einer GUI.

hier nochmal Beispielhaft was ich möchte:

Code: Alles auswählen

# -*- coding: utf-8 -*-

import tkinter
from tkinter.filedialog import askopenfilename

class MyApp(tkinter.Frame):
   
  def __init__(self, master=None):
    tkinter.Frame.__init__(self, master)
    self.grid()
    self.createWidgets()
 
 
  def createWidgets(self):
    self.button = tkinter.Button(root)
    self.button["text"] = "Array Inhalt w�hlen"
    self.button["command"] = self.arrayerstellen
    self.button.grid(row=0,column=1)
 
  def arrayerstellen(self):
    global mein_array
    mein_array = []
    mein_array.append(askopenfilename())
 
  def arraynutzen(self):
       
    i = 0
    while i < (len(mein_array)-1):
      i=i+1
      print(mein_array[i])
 
root = tkinter.Tk()
root.title("wasauchimmer")
app = MyApp(root)
app.mainloop()
Bei jedem Button-Klick erstelle ich das array neu, sodass immer nur ein Wert darin ist.. ich möchte aber, dass dieser reset nicht passiert und jeder Button-Klick das array um einen weitern Wert erweitert. Leider keine Ahnung wie ich das anstelle..
Zuletzt geändert von felopy am Mittwoch 17. Juni 2015, 08:47, insgesamt 3-mal geändert.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@felopy: das "Programm" das Du da gepostet hast ist immer noch nicht lauffähig. Wie soll man da mit einer Antwort ansetzen können, ohne raten zu müssen, was Du wahrscheinlich sonst noch so machst? "self" ist nicht definiert, ein Einrückungen sind kaputt, usw.

Du nutzt ja scheinbar eine Klasse, also ist die Klasse auch der richtige Ort um Dir Deine Liste "mein_array" zu merken.
felopy
User
Beiträge: 17
Registriert: Mittwoch 3. Juni 2015, 08:55

habs editiert
BlackJack

@felopy: Ich denke Du solltest erst einmal Python lernen, also die Grundlagen, und dann ein bisschen in objektorientierter Programmierung (OOP) Fuss fassen, bevor Du eine GUI programmierst. Das Programm ist auf mehreren Ebenen sehr komisch. Bon den Grundlagen her: die ``while``-Schleife in `arraynutzen()` was so niemand in ernsthaft in Python ausdrücken würde. OOP: Eine ”Klasse” die ausser der unnötigerweise ausgelagerten Methode zum erzeugen von Widgets keine *echten* Methoden besitzt. ``global`` was in einer Klasse so überhaupt gar nichts zu suchen hat weil Klassen ja gerade dazu benutzt werden um so etwas zu vermeiden. Ein Wert der in einer Funktion/Methode einfach so aus dem Modul benutzt wird statt als Argument übergeben zu werden (`root`) und der damit die `MyApp`-Klasse noch ein Stück sinnloser macht weil in dem `Frame` den die Klasse beschreibt niemals irgend etwas angezeigt wird.

Und auch bei der GUI-Programmierung ist einiges im Argen. Widgets layouten sich nicht selbst. Kein Widget aus der Standardbibliothek macht das. Damit nimmt man dem Aufrufer der Klasse Entscheidungsspielräume wo und wie das Widget letztendlich dargestellt werden soll. Die Schaltfläche wird unnötig ”gesprächig” erstellt — man könnte Text und Rückruffunktion auch direkt beim Erstellen des Objekts angeben — und das Exemplar wird unnötigerweise an das `MyApp`-Exemplar gebunden.

Mal davon abgesehen das Array der falsche Begriff ist, sollten Grunddatentypen in der Regel nicht in Namen auftauchen, denn wenn man den Typ mal ändert hat man entweder falsche, irreführende Namen im Programm oder muss den Namen überall anpassen. Auch ist `arrayerstellen()` zwar genau das was die Funktion macht (also eigentlich ja eine Liste und kein Array) aber genau das willst Du ja eigentlich gar nicht. Wenn jemand auf die Schaltfläche drückt soll ja keine neue Liste erstellt werden, sondern offenbar möchtest Du das an eine vorhandene, anfangs leere Liste, ein neues Element angehängt wird.
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

BlackJack kam mir zuvor. Nichts desto trotz möchte ich meinen Senf auch abgeben (auch wenn dieser so ziemlich dem von BlackJack entspricht):

Code: Alles auswählen

# -*- coding: utf-8 -*-

## Die Angabe DIESER Kodierung ist nicht notwendig. Python3 verwendet UTF-8 als
## Standardeinstellung. Allerdings sollte man sichergehen, dass die Datei auch
## UTF-8 kodiert ist.
## Die erste Zeile sollte das sogenannte Shebang sein. Dieses wird unter Windows
## normalerweise ignoriert, unixoide Systeme wählen den Interpreter jedoch
## danach aus.

import tkinter
from tkinter.filedialog import askopenfilename

## Per Konvention wird mit 4 Leerzeichen eingerückt.

class MyApp(tkinter.Frame):
  def __init__(self, master=None):
    tkinter.Frame.__init__(self, master)
        ## Es gibt die super()-Funktion zum Initialiserungsaufruf der Eltern-
        ## klasse
    self.grid()
        ## Ein Widget (hier Frame) sollte sich nicht selbst layouten. Dies
        ## sollte immer das übergeordnete Widget übernehmen.
    self.createWidgets()
        ## Die Aufteilung ist in diesem Minimalbeispiel nicht notwendig kann
        ## aber in komplexeren Widgets durchaus sinnvoll sein.

  def createWidgets(self): ## s. o.
    ## Per Konvention sollten Funktions- und Methodennamen
    ## lower_case_with_underscores formatiert werden.
    self.button = tkinter.Button(root)
        ## Es ist nicht nötig, den erzeugten Button an das Widget-Objekt zu
        ## binden. Das dem Button übergeordnete Widget "kennt" seine Kinder.
    self.button["text"] = "Array Inhalt w�hlen"
    self.button["command"] = self.arrayerstellen
        ## Die beiden Zeilen kannst Du in das Erzeugen des Buttons integrieren.
    self.button.grid(row=0,column=1)
        ## Parameter sollten durch Komma+Leerzeichen getrennt werden.

  def arrayerstellen(self):
    ## Die Funktion tut genau das, was ihr Name suggeriert. Es ist nur nicht
    ## das, was du willst, dass sie tut. Auch hier sollte der Name nach
    ## Konvention mit einem underscore versehen werden.
    global mein_array
        ## Vergiss, dass es "global" überhaupt gibt. Vergiss es. Nicht da. Nein.
    mein_array = []
    mein_array.append(askopenfilename())
        ## Du erzeugst eine leere Liste (ein array ist im Python-Kontext etwas
        ## anderes), hängst eine Pfad an und verwirfst diese. Darüber hinaus
        ## ist ``mein_array`` absolut nichts sagend. Interessant ist zu wissen
        ## WAS man hinter dem Namen erwarten kann: Dateinamen.

  def arraynutzen(self):
    ## Namenskonvention
    i = 0
    while i < (len(mein_array)-1):
      i=i+1
      print(mein_array[i])
    ## Ein klassisches Anti-Pattern. Wenn Du die Elemente einer Liste nutzen
    ## möchtest, dann verwende die for-Schleife.
      
root = tkinter.Tk()
root.title("wasauchimmer")
app = MyApp(root)
app.mainloop()
## Code auf Modulebene solltest Du immer vermeiden. Verwende statt dessen das
## s. g. Main-Idiom.
Auf die Gefahr hin, Deinen Lernerfolg zu mindern, ein Umsetzungsvorschlag, um Dich in die richtige Richtung zu schubsen:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from tkinter.filedialog import askopenfilename

class MyFrame(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.filenames = []
            # In dieser Liste (welche an das Widget gebunden wird) werden die
            # Dateinamen gespeichert.
        tk.Button(self, text='Datei wählen', command=self.ask_filename).pack()
        tk.Button(self, text='Verwenden', command=self.use_filenames).pack()

    def ask_filename(self):
        ## Die Methode sollte besser 'add_filename' genannt werden, wie in
        ## einem Folgebetrag erwähnt wird.
        self.filenames.append(askopenfilename())
        
    def use_filenames(self):
        for e in self.filenames:
            print(e)

def main():
    root = tk.Tk()
    frame = MyFrame(root)
    frame.pack()
    root.mainloop()

if __name__ == '__main__':
    main()
Zuletzt geändert von bwbg am Mittwoch 17. Juni 2015, 16:53, insgesamt 1-mal geändert.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Windows mag die Shebang ignorieren, Python unter Windows hat aber inzwischen einen Launcher der die nutzt um den richtigen Interpreter auszuwählen.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

`ask_filename()` würde ich ja eher `add_filename()` nennen, weil da mehr als nur das Erfragen des Dateinamens geschieht. Das Erfragen per GUI ist lediglich der Weg, um an den benötigten Parameter zu kommen. Ziel der Methode ist das Hinzufügen, daher sollte sich dies entsprechend im Namen der Methode wiederfinden.
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

DasIch hat geschrieben:Windows mag die Shebang ignorieren, Python unter Windows hat aber inzwischen einen Launcher der die nutzt um den richtigen Interpreter auszuwählen.
Das wusste ich noch nicht, danke für die Info.
snafu hat geschrieben:`ask_filename()` würde ich ja eher `add_filename()` nennen, weil da mehr als nur das Erfragen des Dateinamens geschieht. Das Erfragen per GUI ist lediglich der Weg, um an den benötigten Parameter zu kommen. Ziel der Methode ist das Hinzufügen, daher sollte sich dies entsprechend im Namen der Methode wiederfinden.
Recht hast du. Ich habe das in meinem Beitrag entsprechend kommentiert.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
felopy
User
Beiträge: 17
Registriert: Mittwoch 3. Juni 2015, 08:55

Danke bwbg,

das ich das array in der init Funktion erstellen muss war der Knackpunkt.
Funzt jetzt alles wie es soll :D
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Nun da Du das weißt, ist es an der Zeit, dass Du Dir Gedanken machst,
  1. warum das so ist und
  2. warum es nicht so funktioniert, wie Du es eingangs probiert hattest.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Antworten