Jest sobie lista ttn, która ląduje w menu, sądziłem że select_ttn
wypisze mi wartość, która zostanie wybrana z menu, ale tak się nie
dzieje. Wygląda na to, że za każdym razem po wybraniu z menu wartości,
wywoływana jest funkcja slect_ttn z ostatnio zapamiętanym parametrem.
Jak spowodować, żeby parametr zmieniał się dynamicznie zgodnie z
wybrem z menu? Albo jaką metodą mogę wyciągnąć wskazywaną w menu
wartość?
<code>
from Tkinter import *
ttn = ('A','B','C','D','E','F')
def select_ttn(k):
print k
root = Tk()
menuTblNames = Menubutton(root,text='menu')
menuLstTtn = Menu(menuTblNames)
menuTblNames.config(menu=menuLstTtn)
for i in ttn:
menuLstTtn.add_radiobutton(label=i, command=(lambda: select_ttn
(i)))
menuTblNames.pack()
root.mainloop()
</code>
dch napisał(a):
> Witam, szukalem odpowiedzi bez rezultatu, moze ktos z Was bedzie znal
> rozwiazanie.
>
> Jest sobie lista ttn, ktora laduje w menu, sadzilem ze select_ttn
> wypisze mi wartosc, ktora zostanie wybrana z menu, ale tak sie nie
> dzieje. Wyglada na to, ze za kazdym razem po wybraniu z menu wartosci,
> wywolywana jest funkcja slect_ttn z ostatnio zapamietanym parametrem.
> Jak spowodowac, zeby parametr zmieniac sie dynamicznie zgodnie z
> wybrem z menu? Albo jaka metoda moge wyciagnac wskazywana w menu
> wartosc?
Musisz pamietac, ze string to w Pythonie obiekt jak kazdy inny
i zawsze poslugujesz sie referencja do niego.
>
> <code>
> from Tkinter import *
> ttn = ('A','B','C','D','E','F')
>
> def select_ttn(k):
> print k
>
> root = Tk()
>
> menuTblNames = Menubutton(root,text='menu')
> menuLstTtn = Menu(menuTblNames)
> menuTblNames.config(menu=menuLstTtn)
>
> for i in ttn:
> menuLstTtn.add_radiobutton(label=i, command=(lambda: select_ttn
> (i)))
Zdefiniowales anonimowa funkcje, ktora korzysta z *referencji* `i`
do obiektu typu `str`. W trakcie obiegu petli *referencja* `i`
wskazuje
na rozne obiekty `str`.
Funkcja anonimowa jest wywolywana po zakonczeniu tej petli,
dopiero w momencie wyboru pozycji menu przez usera.
Na jaki obiekt wskazuje wtedy *referencja* `i`?
>
> menuTblNames.pack()
# dla cwiczenia mozesz sobie tu dopisac
i = 'X'
# i zobaczyc co wyjdzie ;)
> root.mainloop()
> </code>
Przeanalizuj sobie to:
<code>
for i in ttn:
fun1 = lambda: select_ttn('%r (%r)' % (i, id(i)))
fun2 = lambda x=i: select_ttn('%r (%r)' % (x, id(x)))
menuLstTtn.add_radiobutton(label=i, command=fun2)
</code>
RW
> <code>
> for i in ttn:
> fun1 = lambda: select_ttn('%r (%r)' % (i, id(i)))
to wiadomo, będzie działać tak jak powyższym przykładzie
> fun2 = lambda x=i: select_ttn('%r (%r)' % (x, id(x)))
a to jest niezwykłe, oczywiście działa i zupełnie tego nie rozumiem :-
p
do obiektu fun2 przypisane jest wywołanie funkcji select_ttn, która z
kolei korzysta z referencji do obiektu x, który korzysta z referencji
do obiektu i, a ponieważ wywołanie tej funkcji również następuje
dopiero po wykonaniu pętli, dlatego wydaje się, że x powinien odnosić
się, tak samo jak w przypadku fun1, do 'F' (po wykonaniu pętli obiekt
i wskazuje na 'F'), a jednak tak nie jest. Że tak się zapytam, czy to
magia?
> menuLstTtn.add_radiobutton(label=i, command=fun2)
dziękuję za odpowiedź!
>> i = 'X'
>> # i zobaczyc co wyjdzie ;)
> to już wcześniej ćwiczyłem, niestety zawiele mi to nie pomogło,
> pomyślałem wtedy, że funkcja jest wywoływana zawsze z ostatnim
> "zapamiętanym" parametrem i utknąłem.
>
>> <code>
>> for i in ttn:
>> fun1 = lambda: select_ttn('%r (%r)' % (i, id(i)))
> to wiadomo, będzie działać tak jak powyższym przykładzie
>
>> fun2 = lambda x=i: select_ttn('%r (%r)' % (x, id(x)))
> a to jest niezwykłe, oczywiście działa i zupełnie tego nie rozumiem :-
> p
>
> do obiektu fun2 przypisane jest wywołanie funkcji select_ttn, która z
Stop!
Do `fun2` jest przypisane wywołanie anonimowej (nienazwanej) funkcji,
bo do tego służy `lambda` [1]_.
Czyli to jest definicja funkcji anonimowej:
>>> fun1 = lambda: "fun1"
>>> fun1()
'fun1'
>>> fun2 = lambda x: "fun2: %r" % x
>>> fun2('A')
"fun2: 'A'"
a to nazwanej:
>>> def fun1(): return "fun1"
...
>>> fun1()
'fun1'
Funkcja `select_ttn` jest wywoływana wewnątrz funkcji anonimowej
dopiero po wywołaniu tejże anonimowej funkcji.
> kolei korzysta z referencji do obiektu x, który korzysta z referencji
> do obiektu i, a ponieważ wywołanie tej funkcji również następuje
> dopiero po wykonaniu pętli, dlatego wydaje się, że x powinien odnosić
> się, tak samo jak w przypadku fun1, do 'F' (po wykonaniu pętli obiekt
> i wskazuje na 'F'), a jednak tak nie jest. Że tak się zapytam, czy to
> magia?
Różnica polega na tym, że `fun2` przyjmuje domyślny parametr wejściowy.
Wartość takiego parametru jest ustalana tylko raz (w momencie defincji
funkcji). Zauważ, że `fun1` nie przyjmuje żadnego parametru wejściwoego.
Twój problem sprowadza się do tego:
>>> i = 'A'
>>> def f():
... print i
...
>>> def g(x=i):
... print x
...
>>> f()
A
>>> g()
A
>>> i = 'F'
>>> f()
F
>>> g()
A
Funckja `f` cały czas korzysta ze zmiennej `i`. Cokolwiek do niej
przypiszesz, to wyśiwetli funkcja `f`.
Funkcja `g` korzysta ze zmiennej *lokalnej* `x`, która tylko raz
(podczas definicji funkcji `g`) jest zainicjalizowana. Zostanie
do niej przypisane aktualne wskazanie referencji `i` i to się
już później nie ma prawa zmienić.
.. [1] http://docs.python.org/reference/expressions.html#id17
RW
dzięki za wyjaśnienie,
dch