Python2 ссылка перед назначением? - PullRequest
0 голосов
/ 23 сентября 2018

Это дает мне ссылку перед ошибкой присваивания для p1, но не для count?

class Bagadclass:
    def __init__(self):
        print "i n s t a n t i a t e d"
        pass

    def getRegion(self):
        count = [0]
        p1 = [0 , 0]
        p2 = [0 , 0]

        def on_click(x,y,button,pressed):
            count[0] += 1

            if count[0] > 5:
                self.Image = pyautogui.screenshot(region=p1+p2)
                listener.stop()
                pass

            if count[0] == 2:
                p1 = list(pyautogui.position())
                pass

            if count[0] == 4:
                print p1
                p2 = (pyautogui.position()[0] - p1[0] , pyautogui.position()[1] - p1[1])
                pass

            print count , x , y , button , pressed
            pass

        with Listener(on_click=on_click) as listener:
            listener.join()
        pass

Может кто-нибудь объяснить, почему?Я думаю, что речь идет об объекте слушателя или о чем-то, но если он работал для count, я думаю, что он должен работать и для других переменных.

1 Ответ

0 голосов
/ 23 сентября 2018

Функция on_click() является замыканием, имеет доступ к переменным count, p1 и p2, определенным в прилагаемой области действия, getRegion().Эти переменные (count, p1, p2) известны как свободные переменные *, "Если переменная используется в блоке кода , но не определена там ,это свободная переменная " Ссылка 1 .

* На самом деле, в вашем примере только count является свободной переменной;p1 и p2 являются не свободными переменными, так как вы определили их в локальной области действия on_click():

...

if count[0] == 2:
    p1 = list(pyautogui.position()) # <-- here
    pass

if count[0] == 4:
    print p1
    p2 = (pyautogui.position()[0] - p1[0] , pyautogui.position()[1] - p1[1]) # <-- and here

...

И, следовательно, больше не являются свободными переменными, онитеперь локальные переменные .В каждом блоке имя представляет собой либо локальную переменную , либо глобальную переменную , либо свободную переменную .Имя не преобразуется из свободной переменной в локальную переменную после оператора присваивания, вместо этого, если оператор присваивания появляется где-либо внутри блока, имя теперь является локальной переменной.Если вы попытаетесь получить доступ к локальной переменной, которая еще не была связана (то есть выполнение кода еще не достигло оператора присваивания локальной переменной), вы получите исключение UnboundLocalError.

От Модель выполнения - документация по Python 2.7.15 :

Если операция привязки имени происходит где-либо в блоке кода, все варианты использования имени в блоке рассматриваются как ссылки на текущий блок.Это может привести к ошибкам, когда имя используется внутри блока до его привязки.Это правило неуловимо.В Python отсутствуют объявления и разрешены операции привязки имен в любом месте блока кода.Локальные переменные кодового блока могут быть определены путем сканирования всего текста блока на наличие операций связывания имен.

По сути, это в основном означает, что вы можете «обращаться» к свободным переменным (включая изменение / изменение)их), но вы не можете «написать» / перепривязать их, Python интерпретирует это как определение совершенно новой локальной переменной.В Python 3 вы можете решить эту проблему с помощью ключевого слова nonlocal, в противном случае обычной практикой является перенос данных в другую структуру (например, словарь или список), а затем изменениеструктура, чтобы изменить ваши данные вместо этого;таким образом, вы не пытаетесь перепривязать свободную переменную, просто модифицируете объект, к которому она относится.

Это фактически то, что уже было сделано для переменной count, фактическое значение счетчика сохраняется водин список элементов, и когда on_click() необходимо увеличить счетчик, он увеличивает первый элемент списка count (count[0]+=1), вместо того, чтобы пытаться связать его (что-то вроде count+=1 не будет работать).


Пример того, как вы можете пересмотреть свой код (# ! указывает на изменения):

...

    def getRegion(self):
        count = [0]
        p = [[0, 0], [0, 0]]  # [p1, p2]  # !
        def on_click(x,y,button,pressed):
            count[0] += 1
            if count[0] > 5:
                self.Image = pyautogui.screenshot(region=p[0]+p[1])  # !

...

            if count[0] == 2:
                p[0] = list(pyautogui.position())  # !

...

            if count[0] == 4:
                print p[0] # !
                p[1] = (pyautogui.position()[0] - p[0][0],
                        pyautogui.position()[1] - p[0][1])  # !

...

Ссылки:

  1. Модель исполнения - документация по Python 2.7.15
  2. Почему я получаю UnboundLocalError, когда переменная имеет значение?- Документация Python 2.7.15
  3. Как определить свободную переменную в python?
  4. Счетчик Python с замыканием
...