pyqt5 динамически генерирует QCheckBox и связывает действие с новым элементом [duplicate]

Более гибкое решение для создания элементов и связывания событий ( 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
поделиться

6 ответов

На ваш второй вопрос был дан ответ, но что касается вашего первого:

, что точно фиксирует захват?

Scoping in Python является динамическим и лексический. Закрытие всегда будет помнить имя и область действия переменной, а не объект, на который она указывает. Поскольку все функции в вашем примере создаются в одной области и используют одно и то же имя переменной, они всегда ссылаются на одну и ту же переменную.

EDIT: Что касается вашего другого вопроса о том, как преодолеть это, способы, которые приходят на ум:

  1. Наиболее кратким, но не строго эквивалентным способом является , рекомендованный Адриеном Плиссоном . Создайте лямбда с дополнительным аргументом и установите значение по умолчанию для дополнительного аргумента для объекта, который вы хотите сохранить.
  2. Немного более подробный, но менее хакерский - это создать новую область при каждом создании лямбда:
    >>> 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)]
    
122
ответ дан Community 19 August 2018 в 08:13
поделиться
  • 1
    Макс, если вы добавите ответ для моего другого (более простой вопрос), я могу отметить это как принятый ответ. Спасибо! – Boaz 19 February 2010 в 11:25
  • 2
    Python имеет статическую привязку, а не динамическую область. Это всего лишь переменные - это ссылки, поэтому, когда вы устанавливаете переменную в новый объект, сама переменная (ссылка) имеет одно и то же местоположение, но указывает на что-то другое. то же самое происходит в Схеме, если вы set!. см. здесь, для какой динамической области действительно: voidspace.org.uk/python/articles/code_blocks.shtml . – Claudiu 29 June 2010 в 16:21
  • 3
    Вариант 2 напоминает, какие функциональные языки будут вызывать функцию «Curried». – Crashworks 20 September 2011 в 03:15

вы можете заставить захват переменной использовать аргумент со значением по умолчанию:

>>> 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)

146
ответ дан Adrien Plisson 19 August 2018 в 08:13
поделиться
  • 1
    +1 для использования значений по умолчанию. Будучи оцененным при определении лямбда, они делают их идеальными для этого использования. – quornian 13 November 2012 в 23:32
  • 2
    +1 также потому, что это решение, одобренное официальным FAQ . – abarnert 6 November 2014 в 02:24
  • 3
    Это потрясающе. По умолчанию поведение Python не является. – Cecil Curry 3 August 2016 в 01:35

В ответ на ваш второй вопрос самым изящным способом сделать это будет использование функции, которая принимает два параметра вместо массива:

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)
3
ответ дан Chris Lutz 19 August 2018 в 08:13
поделиться
  • 1
    Крис, конечно, этот код не имеет ничего общего с моей оригинальной проблемой. Он построен, чтобы проиллюстрировать мою точку зрения простым способом. Это, конечно, бессмысленно и глупо. – Boaz 19 February 2010 в 11:24

Вот новый пример, который подчеркивает структуру данных и содержимое закрытия, чтобы помочь уточнить, когда закрытый контекст «сохранен».

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
3
ответ дан Jeff 19 August 2018 в 08:13
поделиться
  • 1
    NB Выход 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)
24
ответ дан Joma 19 August 2018 в 08:13
поделиться
  • 1
    Мне очень нравится этот ответ, это самое чистое решение, которое я видел. – Georg Schölly 26 January 2017 в 16:23

Рассмотрим следующий код:

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
16
ответ дан truppo 19 August 2018 в 08:13
поделиться
  • 1
    Это цикл, потому что во многих других языках цикл может создать новую область. – detly 24 June 2010 в 07:35
  • 2
    Этот ответ хорош, потому что он объясняет, почему для каждой лямбда-функции используется одна и та же переменная i. – David Callanan 15 August 2018 в 15:40
Другие вопросы по тегам:

Похожие вопросы: