Функция 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]) # !
...
Ссылки:
- Модель исполнения - документация по Python 2.7.15
- Почему я получаю UnboundLocalError, когда переменная имеет значение?- Документация Python 2.7.15
- Как определить свободную переменную в python?
- Счетчик Python с замыканием