将简短的Python脚本作为函数隔离时,为什么为什么运行方式不同?

时间:2019-08-05 04:29:23

标签: python tkinter

作为在特定Web界面上命中某些点的程序的一部分,此组件使用户可以单击三个点并编写一个配置文件,该文件指示该程序每次运行时将光标精确放置在何处。这些行在程序的主体中时按预期的方式工作(Python 3.6);问题是,我想将它们隔离为一个功能,以便使用户能够选择是否重新配置。 (如果用户没有切换浏览器或调整大小,则可以使用现有的配置文件。)

我希望知识渊博的Pythonista可以帮助我理解为什么仅在适当的地方以 window = Tk()开始缩进这些行,然后将其缩进四个/八个空格并将它们放在函数中会导致它们 运行正常,而不是在第一次调用on_click时挂断电话。 (编辑:来自终端的错误消息在脚本下方)

import threading, pynput, os, configparser
from pynput.mouse import Listener
from tkinter import *
configfile_name = "config.ini"
cfg = configparser.ConfigParser()

def write_config(x_coord, y_coord):
   global configfile_name
   c = open(configfile_name, "a", encoding="utf-8")
   c.write('x=' + x_coord + '\r')
   c.write('y=' + y_coord)
   c.write('\r\n')
   c.close()

def write_first_section(section_name):
   global configfile_name
   c = open(configfile_name, "w", encoding="utf-8")
   c.write('[' + section_name + '] \r')
   c.close()

def write_section(section_name):
   global configfile_name
   c = open(configfile_name, "a", encoding="utf-8")
   c.write('[' + section_name + '] \r')
   c.close()

def on_click(x, y, button, pressed) :
   global count, window, listener
   write_config(str(x), str(y))
   window.after(2000, window.destroy)    
   listener.stop()  

window = Tk()
window.title("Map your screen")
window.geometry('350x80+300+225')
window.lift()
write_first_section('tab')
lbl = Label(window, text="With the QP chat interface screen up,\nclick the 'New' tab at upper left above the blue bar")
lbl.grid(column=0, row=0)
with Listener(on_click=on_click) as listener:
   window.mainloop()
   listener.join()
listener.stop()
write_section('pickup')
window = Tk()
window.title("Step two!")
window.geometry('350x80+300+225')
window.lift()
lbl = Label(window, text="Now, click just below the blue bar")
lbl.grid(column=0, row=0)
with Listener(on_click=on_click) as listener:
   window.mainloop()
   listener.join()
listener.stop()
write_section('paste')
window = Tk()
window.title("Step three!")
window.geometry('350x80+300+225')
window.lift()
lbl = Label(window, text="Lastly, click in the text box")
lbl.grid(column=0, row=0)
with Listener(on_click=on_click) as listener:
   window.mainloop()

当放置在函数中时,脚本会引发以下错误:

Unhandled exception in listener callback
Traceback (most recent call last):
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/__init__.py", line 157, in inner
    return f(self, *args, **kwargs)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/xorg.py", line 458, in _handler
    self._handle(self._display_stop, event)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/mouse/_xorg.py", line 141, in _handle
    self.on_click(px, py, self._button(event.detail), True)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/__init__.py", line 78, in inner
    if f(*args) is False:
  File "does_it_all.py", line 37, in on_click
    window.after(2000, window.destroy)
NameError: name 'window' is not defined
Traceback (most recent call last):
  File "does_it_all.py", line 231, in <module>
    map()
  File "does_it_all.py", line 192, in map
    listener.join()
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/__init__.py", line 205, in join
    six.reraise(exc_type, exc_value, exc_traceback)
  File "/home/bruce/.local/lib/python3.6/site-packages/six.py", line 692, in reraise
    raise value.with_traceback(tb)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/__init__.py", line 157, in inner
    return f(self, *args, **kwargs)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/xorg.py", line 458, in _handler
    self._handle(self._display_stop, event)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/mouse/_xorg.py", line 141, in _handle
    self.on_click(px, py, self._button(event.detail), True)
  File "/home/bruce/.local/lib/python3.6/site-packages/pynput/_util/__init__.py", line 78, in inner
    if f(*args) is False:
  File "does_it_all.py", line 37, in on_click
    window.after(2000, window.destroy)    
NameError: name 'window' is not defined

当我尝试将on_click(....)函数定义之后的所有内容放入一个称为map()的函数中,然后尝试运行map()时,在将[tab]写入config.ini文件后,它挂起了,使第一个窗口停留在屏幕上。但是,当我如上所述运行它时,它会在所有三个窗口中正常运行并写入配置文件的所有三个部分。 我确定脚本中存在严重的错误,但是:为什么为什么这32行在开放时运行良好,而在包含函数时就中断了呢? 感谢您的帮助和建设性的指责!

1 个答案:

答案 0 :(得分:0)

将这些行移动到函数中时,您定义的window(和listener)变量不再是全局变量,而成为该函数的局部变量。您的on_click函数依赖于window(和listener)进行全局定义,并且由于它们不再作为全局变量存在,因此您的代码中断了。

最小的解决方法是添加:

global window, listener

位于新函数的顶部,因此它将windowlistener视为全局变量,而不是将它们视为局部变量的默认行为。

一种更彻底的解决方案是编写一个类,其中windowlistener(可能还有其他)是实例属性,可以通过self使用新函数和{{ 1}}是该类的方法。在这种情况下并不重要,但是只要您发现自己依赖on_click来实现可变的全局状态,通常这是一个糟糕的设计,并且您确实真的想要一个类。