Это имеет мало общего с самим Tkinter. Он также не столько связан с lambda
, сколько с Python в целом.
Возьмите оба из уравнения и рассмотрите следующую программу на Python:
def f(x=3, y=4):
print('x =', x, 'y =', y)
f(0, 0)
f(0)
f()
Если предположить, что Python 3 (или from __future__ import print_function
) при запуске выдает:
x = 0 y = 0
x = 0 y = 4
x = 3 y = 4
Это потому, что первый вызов f
проходит 0, 0
, поэтому x
и y
оба связаны с нулем. второй вызов f
передает только 0
, поэтому x
связан с 0
, а y
связан со значением по умолчанию, равным 4. Вызов третий вообще ничего не передает, а x
и y
оба связаны со значениями по умолчанию.
(Пока все должно быть достаточно ясно.)
Теперь давайте немного с этим суетимся. Я продолжу предполагать Python 3, так что input
означает, что в Python 2 мы должны использовать raw_input
для достижения:
def f(x=input('enter default x: '), y=input('enter default y: ')):
print('x =', x, 'y =', y)
print('about to call f three times')
f(0, 0)
f(0)
f()
Прежде чем запускать этот пример программы, подумайте, что вы ожидаете от него. Затем запустите его - вот мой результат:
$ python3 t.py
enter default x: hello
enter default y: world
about to call f three times
x = 0 y = 0
x = 0 y = world
x = hello y = world
Почему это считывало значения по умолчанию для x
и y
до того, как мы даже назвали его в первый раз? Почему не считывает новые значения по умолчанию для x
и y
при каждом вызове?
Подумайте об этом немного, затем прочитайте
Действительно, сделай это. Спросите , почему входы происходили в эти нечетные времена.
Теперь, когда вы об этом подумали ...
Это сделал сделал это, хотя. Это ключ здесь. значения по умолчанию для ваших аргументов фиксируются во время выполнения оператора def
. Оператор def
, который связывает имя f
с нашей функцией, на самом деле является run , когда Python загружает файл, увидев тело функции. Сама функция запускается позже, после того, как Python получил вызов print
, а затем первый вызов f
.
A lambda
в Python - это просто своего рода определение анонимной функции. Вместо:
def square(x):
return x * x
мы можем написать:
square = lambda x: x * x
Выражение lambda
определяет новый функциональный элемент, лямбда-функцию - вы не можете использовать операторы типа if
/ else
внутри одного из них, просто выражения, и они автоматически возвращать значение их выражения. В этом случае наша лямбда-функция имеет один аргумент с именем x
. Функция возвращает x * x
.
Внешнее присваивание, square =
, связывает эту лямбда-функцию с именем square
, как если бы мы вместо этого сделали def square(x)
. Так что это в основном просто синтаксический трюк: у нас может быть реальная функция, такая как square
, с аргументами, или ограниченная лямбда-функция, которая может использовать только выражения, как эта анонимная функция, которую мы почти сразу связываем с именем square
.
Хотя часть аргументов работает одинаково. Так же, как с f
и input
, если мы связываем x
:
square = lambda x=3: x * x
или
square = lambda x=int(input('choose a default for x now> ')): x * x
это происходит просто один раз , когда выполняется само выражение lambda
. Функция теперь содержит переменную x
со значением по умолчанию.
Когда позже мы вызовем функцию, мы можем предоставить значение для x
или оставить его по умолчанию. Если мы не предоставляем значение, Python использует значение по умолчанию, которое он захватил ранее , когда мы выполняли строку с lambda
в нем, а не сейчас, когда мы вызываем лямбда-функцию.
Это относится и к Ткинтеру. Вы написали:
input_box2.bind('<FocusOut>', lambda i=inp_var2.get(): test2(i, inp_var2.get()))
но это почти то же самое, что писать:
def f(i=inp_var2.get()):
test2(i, inp_var2.get())
input_box2.bind('<FocusOut>', f)
за исключением того, что вам не нужно придумывать здесь имя функции f
. Лямбда-вариант функции не имеет имени, но это все же просто функция. (В этом отношении, когда мы делаем square = lambda ...
, лямбда-функция не имеет имени. Имя square
- это имя переменной, а не имя функции. Переменная просто связана с функция, так что square(10)
вызывает ее.)
В любом случае, позже , когда Tkinter имеет событие, которое соответствует <FocusOut>
, Tkinter вызывает f
... или, если вы использовали lambda
, вызывает вашу безымянную лямбда-функцию.Tkinter предоставляет один аргумент этой функции;единственный аргумент, который он предоставляет - это событие.Таким образом, значение по умолчанию для i
в f
выше не имеет значения - вы можете сделать:
def f(i=None):
test2(i, inp_var2.get())
или:
def f(i='hello world'):
test2(i, inp_var2.get())
, потому что когда Tkinter вызывает f
, оно всегдапредоставляет фактический аргумент для i
.