Hallo, ich habe ein Problem. Ich will eine Funktion aus einer anderen Python Datei aufrufen. Der Code sieht folgendermaßen aus: import Functions as fts ##Importieren der Datei. ... Button1 = Button(window, text="Move", bg="white", fg="black", command=fts.moveforward) Button1.grid(column=3, row=1) In der Functions.py sieht es so aus: def moveforward(): .... Wenn ich das Programme starte, kommt folgende Fehlermeldung: AttributeError: module 'Functions' has no attribute 'moveforward' So wie ich die Fehlermeldung verstehe, findet er die Funktion nicht, obwohl diese eindeutig vorhanden ist. Woran könnte es liegen? Danke für eure Hilfe im Voraus.
Die Ursache liegt möglicherweise in dem was Du uns nicht erzählst. Poste doch einfach mal den vollständigen Code so wie er nicht funktioniert, gerne um alles unnötige gekürzt, soweit gekürzt bis nur noch das Nichtfunktionieren als solches enthalten und klar ersichtlich ist, poste nicht in umständlicher Prosa umschrieben was Du denkst was im Code steht sondern poste einfach den echten nackten Code unverfälscht. Es könnte auch geschehen daß Du beim Kürzen aufs Wesentliche, beim Vorbereiten eines Minimalbeispiels den Fehler selbst findest. Deshalb ist das immer der erste Schritt den man tun sollte!
:
Bearbeitet durch User
hier der relevante Quellcode: gui.py: from tkinter import * import Functions as fts from config import * window = Tk() window.title("Steuerung") window.geometry("640x480") # Steigung1= Steigung Label1 = Label(window, text="Motor, Position:", font=("Arial", 14)) Label1.grid(column=0, row=1) Labelp1 = Label(window, text=pos1, font=("Arial", 14)) Labelp1.grid(column=1, row=1) Spin1 = Spinbox(window, from_=-20, to=20, width=5) Spin1.grid(column=2,row=1) Button1 = Button(window, text="Move", bg="white", fg="black", command=fts.moveforward) Button1.grid(column=3, row=1) Functions.py: from config import * import gui import sys import os import re def moveforward(): textfile = open("Position_Motor_1.txt","r") pos1= textfile.read() pos1 = int(pos1) print('Motor 1 bewegt sich',spin1.get(), 'mm') mm=int(spin1.get()) pos= check(pos1, mm,pinsM1) Labelp1.configure(text=pos) textfile = open('Position_Motor_1.txt','w') pos = str(pos) textfile.write(pos) textfile.close() pos = int(pos) Fehlermeldung: AttributeError: module 'Functions' has no attribute 'moveforward' Es gibt noch eine dritte Pythondatei: Config.py. Dort sind nur Variablen.
:
Bearbeitet durch User
Es wird lauffähiger Code zur Analyse benötigt. In deinem Dump fehlt Config.py.
Max A. schrieb: >Button1=Button(window,text="Move",bg="white",fg="black",command=fts.mov eforward) Du rufst hier moveforward als Variable und nicht als Funktion bzw. Methode auf.
1 | Button1 = Button(window, text="Move", bg="white", fg="black", command=fts.moveforward()) |
Probier das mal Edit: Deine Funktion moveforward hat keinen Rückgabeparamter?!
:
Bearbeitet durch User
Max A. schrieb: > Fehlermeldung: > > AttributeError: module 'Functions' has no attribute 'moveforward' was gibt denn dir(Function) aus ? ist in der liste moveforward dabei.
Chris M. schrieb: > Du rufst hier moveforward als Variable und nicht als Funktion bzw. > Methode auf. Das ist vollkommen in Ordnung. Der Fehler liegt in Code, der wieder nicht gezeigt wird.
Chris M. schrieb: > Max A. schrieb: >>Button1=Button(window,text="Move",bg="white",fg="black",command=fts.mo v eforward) > > Du rufst hier moveforward als Variable und nicht als Funktion bzw. > Methode auf. > > Button1 = Button(window, text="Move", bg="white", fg="black", > command=fts.moveforward()) > > Probier das mal > Edit: Deine Funktion moveforward hat keinen Rückgabeparamter?! Hab ich versucht. Hat leider nicht funktioniert. Nein meine Funktion hat keinen Rückgabewert. Brezel schrieb: > Es wird lauffähiger Code zur Analyse benötigt. > In deinem Dump fehlt Config.py. Zum Testen braucht man noch folgende Funktion auf aus der Function.py import gui def check(pos,mm,pin): P=pos+mm if min<=P<=max: print("ok") else: print("nicht ok") pass return pos config.py: min=0 max=30 # pinsM1=[17, 4,27,22] textfile = open("Position_Motor_1.txt","r") pos1= textfile.read() pos1 = int(pos1) textfile.close() Ich habe noch die entsprechende Textdatei angelegt. Dort hab ich z.B 12 eingetragen imonbln schrieb: > Max A. schrieb: >> Fehlermeldung: >> >> AttributeError: module 'Functions' has no attribute 'moveforward' > > was gibt denn dir(Function) aus ? ist in der liste moveforward dabei. Die Funktion soll erstmal überprüfen, ob die neue Position im gewünschten Bereich liegt. Wenn ja, soll sich der Motor bewegen. Anschließend wird die neue Position in die Textdatei geschrieben. Einen Rückgabewert gibt es nicht. Welche Liste?
:
Bearbeitet durch User
Max A. schrieb: > hier der relevante Quellcode: Nein, der relevante Code würde wie folgt aussehen: gui.py
1 | from tkinter import * |
2 | import functions as fts |
3 | |
4 | window = Tk() |
5 | window.title("Steuerung") |
6 | window.geometry("640x480") |
7 | |
8 | button_mv = Button(window, text="Move", bg="white", fg="black", command=fts.move_fwd) |
9 | button_mv.pack() |
10 | |
11 | window.mainloop() |
functions.py
1 | def move_fwd(): |
2 | print("Boom!") |
Und das funktioniert anstandslos
Karl schrieb: > Max A. schrieb: >> command=fts.moveforward) > > Wie wär es mit einer Klammer? > command=fts.moveforward() Hab ich versucht. Geht leider nicht. Eric B. schrieb: > Max A. schrieb: >> hier der relevante Quellcode: > > Nein, der relevante Code würde wie folgt aussehen: > > gui.pyfrom tkinter import * > import functions as fts > > window = Tk() > window.title("Steuerung") > window.geometry("640x480") > > button_mv = Button(window, text="Move", bg="white", fg="black", > command=fts.move_fwd) > button_mv.pack() > > window.mainloop() > > functions.pydef move_fwd(): > print("Boom!") > Und das funktioniert anstandslos Hier nochmal wie meine drei Pythondateien aufgebaut sind: gui.py: from tkinter import * import Functions as fts from config import * window = Tk() window.title("Steuerung") window.geometry("640x480") # Steigung1= Steigung Label1 = Label(window, text="Motor, Position:", font=("Arial", 14)) Label1.grid(column=0, row=1) Labelp1 = Label(window, text=pos1, font=("Arial", 14)) Labelp1.grid(column=1, row=1) Spin1 = Spinbox(window, from_=-20, to=20, width=5) Spin1.grid(column=2,row=1) Button1 = Button(window, text="Move", bg="white", fg="black", command=fts.moveforward) Button1.grid(column=3, row=1) Button1.pack() window.mainloop() Functions.py: from config import * import gui import sys import os import re def check(pos,mm,pin): P=pos+mm if min<=P<=max: print("ok") else: print("nicht ok") pass return pos def moveforward(): textfile = open("Position_Motor_1.txt","r") pos1= textfile.read() pos1 = int(pos1) print('Motor 1 bewegt sich',spin1.get(), 'mm') mm=int(spin1.get()) pos= check(pos1, mm,pinsM1) Labelp1.configure(text=pos) textfile = open('Position_Motor_1.txt','w') pos = str(pos) textfile.write(pos) textfile.close() pos = int(pos) config.py: min=0 max=30 pinsM1=[17, 4,27,22] textfile = open("Position_Motor_1.txt","r") pos1= textfile.read() pos1 = int(pos1) textfile.close() Fehlermeldung: AttributeError: module 'Functions' has no attribute 'moveforward' Wenn ich die Funktion in die gui.py kopiere, funktioniert es problemlos. Nur wenn diese Funktion in einer anderen Pythondatei ist dann funktioniert es nicht. Bei meinem Programm will ich die Oberfläche, Funktionen und Variablen getrennt haben.
Liegen alle Dateien in einem Ordner? Oder hast du irgendeine Pythondatei in Unter/Überordner?
Die Dateien sind alle im selben Ordner.
Max A. schrieb: >gui.py: > >from tkinter import * >import Functions as fts > Functions.py: > > from config import * > import gui Du hast eine Zirkelbezug gebaut!
Karl schrieb: > Max A. schrieb: >>gui.py: >> >>from tkinter import * >>import Functions as fts > >> Functions.py: >> >> from config import * >> import gui > > Du hast eine Zirkelbezug gebaut! Stimmt. importiere alle Module in der Config und greife von deinen Dateien dann über die Config drauf zu. Dafür ist sie da. Beispiel config.py:
1 | import Functions as fts |
Beispiel in gui.py
1 | import config |
2 | |
3 | config.fts.moveforward() #Funktionsaufruf ueber config |
Chris M. schrieb: > importiere alle Module in der Config und greife von deinen Dateien dann > über die Config drauf zu. Dafür ist sie da. Nein struckturiere deine Module, sodass man so einen Quatsch nicht braucht, oder mach gleich ordentlich objektorientiert!
Karl schrieb: > Max A. schrieb: >>gui.py: >> >>from tkinter import * >>import Functions as fts > >> Functions.py: >> >> from config import * >> import gui > > Du hast eine Zirkelbezug gebaut! Auf die gui muss ich nur zugreifen, da ich den Wert von der Spinbox brauche
Max A. schrieb: > Auf die gui muss ich nur zugreifen, da ich den Wert von der Spinbox > brauche Dann übergibt der Funktion die Spinbox oder den Wert!
1 | def moveforward(MySpin): |
2 | textfile = open("Position_Motor_1.txt","r") |
3 | pos1= textfile.read() |
4 | pos1 = int(pos1) |
5 | print('Motor 1 bewegt sich',MySpin.get(), 'mm') |
6 | mm=int(MySpin.get()) |
7 | pos= check(pos1, mm,pinsM1) |
8 | Labelp1.configure(text=pos) |
9 | textfile = open('Position_Motor_1.txt','w') |
10 | pos = str(pos) |
11 | textfile.write(pos) |
12 | textfile.close() |
13 | pos = int(pos) |
Insgesamt wirkt das alles sehr unstrukturiert! Trenne Datenverarbeitung, Daten und Gui richtig voneinander!
Karl schrieb: > Dann übergibt der Funktion die Spinbox oder den Wert! Ganz so einfach wirds nicht gehen, Python kann erstmal kein currying, da braucht er noch ne Hilfsfunktion die eine neue Funktion erzeugt und zurückliefert.
Bernd K. schrieb: > Ganz so einfach wirds nicht gehen, Python kann erstmal kein currying, da > braucht er noch ne Hilfsfunktion die eine neue Funktion erzeugt und > zurückliefert. Ich verstehe dein Problem nicht. Natürlich geht das, so wie ich es geschrieben habe. Man kann in Python einer Funktion einfach ein Objekt übergeben. Und in Python gibt es noch lambda, was man hier aber nicht braucht.
Abgesehen davon hat der Zugriff auf die Spinbox eigentlich nichts in der Funktion zu suchen, es würde reichen, wenn man den Wert übergibt. Auch der Dateiname hat in der Funktion nichts zu suchen, sonst schreibt man für jeden Motor eine Funktion.
Karl schrieb: > Ich verstehe dein Problem nicht. Natürlich geht das, so wie ich es > geschrieben habe. Man kann in Python einer Funktion einfach ein Objekt > übergeben. Du sollst dem Button-Konstruktor aber eine Funktion übergeben und dabei nicht die selbige schon aufrufen. Also mußt Du die Funktion mitsamt ihrem Argument aber im noch nicht aufgerufenen Zustand übergeben! Also eine Funktion die den Parameter schon hat aber noch nicht aufgerufen wurde! So daß der Button sie später aufrufen kann! Der Fachbegriff dafür ist Currying und partielle Funktionsauswertung Google das! Und dann probier Deinen eigenen naiven Vorschlag ruhig einfach mal aus und schau Dir die Fehlermeldungen an! Ich hab Deinen Code mal entsprechend geändert so daß er die teilangewendete Funktion zurückliefert, so könnts gehen:
1 | def moveforward_curry(MySpin): |
2 | def moveforward(): |
3 | textfile = open("Position_Motor_1.txt","r") |
4 | pos1= textfile.read() |
5 | pos1 = int(pos1) |
6 | print('Motor 1 bewegt sich',MySpin.get(), 'mm') |
7 | mm=int(MySpin.get()) |
8 | pos= check(pos1, mm,pinsM1) |
9 | Labelp1.configure(text=pos) |
10 | textfile = open('Position_Motor_1.txt','w') |
11 | pos = str(pos) |
12 | textfile.write(pos) |
13 | textfile.close() |
14 | pos = int(pos) |
15 | return moveforward |
Das liefert eine Closure zurück die den korrekten Wert für MySpin bereits enthält aber selbst noch nicht aufgerufen wurde. Diese kann dann wiederum an den Button übergeben werden so daß er sie später bei Klick aufrufen kann. Und schon hast Du wieder was gelernt, man lernt nie aus! Das macht die Sache interessant!
:
Bearbeitet durch User
geht übrigens auch so:
1 | from functools import partial |
2 | |
3 | ... |
4 | |
5 | Button1 = Button(window, text="Move", bg="white", fg="black", |
6 | command=partial(fts.moveforward, MySpin)) |
Dann muss moveforward ein Argument akzeptieren (so wie in Deinem Beispiel) und partial() liefert dann eine neue Funktion zurück bei der das erste Argument schon ausgefüllt ist und die man dann später ohne Argumente aufrufen kann.
Bernd K. schrieb: > Du sollst dem Button-Konstruktor aber eine Funktion übergeben und dabei > nicht die selbige schon aufrufen. Jetzt verstehe was du von mir willst. Ich habe mir das Programm nicht wirklich angeschaut, dass command= eine Funktion sein soll habe ich nicht angenommen, ich dacht command soll ein (Rückgabe-)Wert sein. Bernd K. schrieb: > Und dann probier Deinen eigenen naiven Vorschlag ruhig > einfach mal aus und schau Dir die Fehlermeldungen an! War nicht mein Vorschlag, wie gesagt hätte ich das ganze Programm komplett anders strukturiert. Ich hätte wahrscheinlich irgendein Objekt dem man beim Initialisieren die Spinbox mitgibt und dann halt eine Funktion, die man einfach aufrufen kann wenn der Button gedrückt wird.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.