Более гибкое решение для создания элементов и связывания событий ( source )
// creating a dynamic element (container div)
var $div = $("", {id: 'myid1', class: 'myclass'});
//creating a dynamic button
var $btn = $("
190
задан martineau 15 April 2017 в 01:54
поделиться
На ваш второй вопрос был дан ответ, но что касается вашего первого:
, что точно фиксирует захват?
blockquote>Scoping in Python является динамическим и лексический. Закрытие всегда будет помнить имя и область действия переменной, а не объект, на который она указывает. Поскольку все функции в вашем примере создаются в одной области и используют одно и то же имя переменной, они всегда ссылаются на одну и ту же переменную.
EDIT: Что касается вашего другого вопроса о том, как преодолеть это, способы, которые приходят на ум:
- Наиболее кратким, но не строго эквивалентным способом является , рекомендованный Адриеном Плиссоном . Создайте лямбда с дополнительным аргументом и установите значение по умолчанию для дополнительного аргумента для объекта, который вы хотите сохранить.
- Немного более подробный, но менее хакерский - это создать новую область при каждом создании лямбда:
Область здесь создается с использованием новой функции (лямбда, для краткости), которая связывает ее аргумент и передает значение, которое вы хотите связать в качестве аргумента. Однако в реальном коде вы, скорее всего, будете иметь обычную функцию вместо лямбда для создания новой области:>>> adders = [0,1,2,3] >>> for i in [0,1,2,3]: ... adders[i] = (lambda b: lambda a: b + a)(i) ... >>> adders[1](3) 4 >>> adders[2](3) 5
def createAdder(x): return lambda y: y + x adders = [createAdder(i) for i in range(4)]
вы можете заставить захват переменной использовать аргумент со значением по умолчанию:
>>> for i in [0,1,2,3]:
... adders[i]=lambda a,i=i: i+a # note the dummy parameter with a default value
...
>>> print( adders[1](3) )
4
Идея состоит в том, чтобы объявить параметр (умно названный i
) и присвоить ему значение по умолчанию переменную, которую вы хотите захватить (значение i
)
В ответ на ваш второй вопрос самым изящным способом сделать это будет использование функции, которая принимает два параметра вместо массива:
add = lambda a, b: a + b
add(1, 3)
Однако, используя lambda здесь немного глупо. Python дает нам модуль operator
, который обеспечивает функциональный интерфейс для основных операторов. Лямбда выше имеет лишние накладные расходы, просто для вызова оператора сложения:
from operator import add
add(1, 3)
Я понимаю, что вы играете, пытаясь изучить язык, но я не могу представить ситуацию, которую я бы использовал массив функций, в которых может возникнуть странная видимость Python.
Если бы вы захотели, вы могли бы написать небольшой класс, который использует ваш синтаксис индексирования массива:
class Adders(object):
def __getitem__(self, item):
return lambda a: a + item
adders = Adders()
adders[1](3)
Вот новый пример, который подчеркивает структуру данных и содержимое закрытия, чтобы помочь уточнить, когда закрытый контекст «сохранен».
def make_funcs():
i = 42
my_str = "hi"
f_one = lambda: i
i += 1
f_two = lambda: i+1
f_three = lambda: my_str
return f_one, f_two, f_three
f_1, f_2, f_3 = make_funcs()
Что находится в закрытии?
>>> print f_1.func_closure, f_1.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Примечательно, что my_str не находится в закрытии f1.
Что находится в закрытии f2?
>>> print f_2.func_closure, f_2.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Обратите внимание (из адресов памяти), что оба закрытия содержат одинаковые объекты. Итак, вы можете запустить , чтобы думать о лямбда-функции как о ссылке на область. Однако my_str не находится в замыкании для f_1 или f_2, а i не находится в замыкании для f_3 (не показано), что предполагает, что объекты замыкания сами по себе являются отдельными объектами.
Являются ли сами объекты замыкания тот же объект?
>>> print f_1.func_closure is f_2.func_closure
False
int object at [address X]>
заставлял меня думать, что закрытие хранит [адрес X] AKA ссылку. Однако [адрес X] изменится, если переменная будет переназначена после оператора лямбда.
– Jeff
13 May 2014 в 22:35
Для полноты другого ответа на ваш второй вопрос: вы можете использовать partial в модуле functools .
При импорте add от оператора в качестве Криса Лутца предлагается пример:
from functools import partial
from operator import add # add(a, b) -- Same as a + b.
adders = [0,1,2,3]
for i in [0,1,2,3]:
# store callable object with first argument given as (current) i
adders[i] = partial(add, i)
print adders[1](3)
Рассмотрим следующий код:
x = "foo"
def print_x():
print x
x = "bar"
print_x() # Outputs "bar"
Я думаю, что большинство людей не найдут это сбивающим с толку. Это ожидаемое поведение.
Итак, почему люди думают, что это будет иначе, когда это будет сделано в цикле? Я знаю, что сама совершила эту ошибку, но я не знаю почему. Это петля? Или, может быть, лямбда?
В конце концов, цикл представляет собой только более короткую версию:
adders= [0,1,2,3]
i = 0
adders[i] = lambda a: i+a
i = 1
adders[i] = lambda a: i+a
i = 2
adders[i] = lambda a: i+a
i = 3
adders[i] = lambda a: i+a
i
.
– David Callanan
15 August 2018 в 15:40
set!
. см. здесь, для какой динамической области действительно: voidspace.org.uk/python/articles/code_blocks.shtml . – Claudiu 29 June 2010 в 16:21