Frage zu ´command=´ im Zusammenhang mit for-Schleifen

Fragen zu Tkinter.
Antworten
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Hallo!

Ich bin dabei ein Programm zu schreiben, dass Sounds abspielt, sobald man auf diesen Button klickt.

Dafür hab ich eine Prozedur

Code: Alles auswählen

def play_sound(name)
mit der ich entsprechende Sounds abspielen lassen kann.
Danach habe ich Buttons erstellt etc.

Code: Alles auswählen

def play_test01(e):
    play_sound('test01')
But=Button(root, text = 'test01')
But.pack()
Widget.bind(But, '<Button-1>', play_test01)
Das funktioniert wunderbar, jedoch will ich nicht für für jeden Sound eine eigene Prozedur!

Das ganze will ich jetzt über eine for-Schleife lösen:

Code: Alles auswählen

titel=['test01', 'test02']
for tit in titel:
    Button(root, command= play_sound(tit), text=tit).pack()
Dabei passiert folgendes:
Der Sound wird abgespielt, danach erscheint der Button.
Wird der Button geklickt, so passiert nichts.

Eine andere Variante:

Code: Alles auswählen

for tit in titel:
    Button(root, command=lambda: play_sound(tit), text=tit).pack()
Dabei passiert folgendes:
Die Button erscheinen. Klickt man einen diesen Button an, so wird 'test02' abgespielt, obwohl die Beschriftung stimmt!


Kann mir jemand sagen, was ich verändern muss?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ja, die Idee mit "lambda" war schon nicht schlecht, dass macht aber beim Erzeugen von Funktionen Probleme. Ich empfehle daher die Funktion "partial" aus dem "functools"-Modul:

Code: Alles auswählen

import functools
...
for tit in titel:
    Button(root, command=functools.partial(play_sound, tit), text=tit).pack()
Edit: habe noch mal kurz über deinen Code geschaut, da sind mir noch ein paar Dinge aufgefallen:

- wähle besser aussagekräftige Bezeichner; "But" ist ein wirklich nichtssagender Name für einen Button; außerdem sollte du dich für eine Sprache entscheiden: Deutsch oder Englisch.
- "Variablennamen" solltest du klein schreiben: Statt "But" also "but".
- um die Leerzeichen bei Zuweisungen solltest du Leerzeichen setzen, bei Parametern allerdings nicht
- die Letzten beiden Punkte, und noch etwas mehr, kannst du auch in PEP8 nachlesen.
Das Leben ist wie ein Tennisball.
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Danke für deine Antwort

Aber ist das richtig so:

Code: Alles auswählen

>>> import functools
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in ?
    import functools
ImportError: No module named functools
Ist das nicht bei den Standardmodulen dabei?

zum Edit:
"But" kann ich ja weglassen, das war eh nur als temporärer Name gedacht.
Das mit Deutsch und Englisch... jaaaa... ;)
ich werd mich bemühen

Immerhin bin ich schon vom *-import weggekommen :D
BlackJack

@Pascal: Wie alt ist denn Dein Python? Das Modul gibt es seit 2.5.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

http://docs.python.org/library/functools

Dort ist der erste Satz:
New in version 2.5.
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Ich hab 2.4

Na Toll
Ich kann aber nicht finden, wo man das noch runterladen kann...
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Pascal hat geschrieben:Ich hab 2.4

Na Toll
Ich kann aber nicht finden, wo man das noch runterladen kann...
Was für ein "das"? Du meinst doch nicht etwa Python >2.4? :shock:
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Ich hab die Version 2.4
mal schauen was sich machen lässt...
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Ok 2.6 runtergeladen.. morgen geht´s weiter
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

numerix hat geschrieben:
Was für ein "das"? Du meinst doch nicht etwa Python >2.4? :shock:
ich meinte das modul
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Hallo Leute,

gerade frage ich mich, wie ohne "partial" auskommt, wenn man eine Funktion mit Parametern aufrufen will. Dies gilt speziell für Tkinter, wenn 'event' bereits ein Parameter ist.


Grund ist, dass wir in der Schule 2.4 haben, also ohne functools :evil:

Was kann ich machen?
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Zur Not kannst du dir ja die Funktion aus der Dokumentation herauskopieren.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

jbs hat geschrieben:Zur Not kannst du dir ja die Funktion aus der Dokumentation herauskopieren.
schön wärs:

Aus dem functools-Modul:

Code: Alles auswählen

from _functools import partial, reduce
...
def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):
...
def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
schade... :twisted:
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Code: Alles auswählen

def play_sound(title):
    print "playing ", title

for title in ["foo", "bar"]:
    def _play(e):
        play_sound(title)
    Button(root, command=_play, text=title).pack()
Oder auch die "lambda e,title=title: play_sound(title)" Variante. Dadurch wird das Argument gebunden und die Variable nicht überschrieben.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Pascal hat geschrieben:schön wärs:
http://docs.python.org/library/functools.html hat geschrieben:functools.partial(func[, *args][, **keywords])
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords. If more arguments are supplied to the call, they are appended to args. If additional keyword arguments are supplied, they extend and override keywords. Roughly equivalent to:

Code: Alles auswählen

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

cofi hat geschrieben:

Code: Alles auswählen

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc
ich weiß nicht, was ich mit dem Rückgabewert anfangen soll... :oops:
BlackJack

@Pascal: An einen Namen binden!? Als Argument übergeben, zum Beispiel als `command`-Argument bei `Tkinter`-Buttons!? Darum ging's doch in diesem Thema, oder?
Antworten