这为我提供了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
,我认为它也应适用于其他变量。
答案 0 :(得分:0)
函数on_click()
是一个闭包,它可以访问在封闭范围count
中定义的变量p1
,p2
和getRegion()
。这些变量(count
,p1
,p2
)被称为 free变量 *,“如果代码块中使用了变量,则 在那里没有定义,它是一个自由变量” Link 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
异常。
来自Execution model — Python 2.7.15 documentation:
如果在代码块内的任何地方进行了名称绑定操作,则该块内对该名称的所有使用均被视为对当前块的引用。在绑定名称之前在块中使用名称时,这可能导致错误。这条规则很微妙。 Python缺少声明,并且允许名称绑定操作发生在代码块内的任何位置。可以通过扫描代码块的整个文本以进行名称绑定操作来确定代码块的局部变量。
从本质上讲,这基本上意味着您可以“访问”自由变量(包括对其进行修改/突变),但不能“写入” /重新绑定它们,Python会将其解释为定义了一个全新的局部变量。在Python 3中,您可以使用nonlocal
关键字解决此问题,否则common practice会将您的数据包装在另一个结构(例如字典或列表)中,然后修改该结构以更改您的数据;这样,您就不会尝试重新绑定自由变量,而只是修改它所引用的对象。
这实际上是对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]) # !
...
链接: