[英]Why does short Python script run differently when it's isolated as a function?
As part of a program that hits some points on a particular web interface, this component enables the user to click three spots & writes a config file that instructs the program precisely where to put the cursor each time it runs. 作为在特定Web界面上命中某些点的程序的一部分,此组件使用户可以单击三个点并编写一个配置文件,该文件指示该程序每次运行时将光标精确放置在何处。 These lines work as intended (Python 3.6) when they're in the main body of the program;
这些行在程序的主体中时按预期的方式工作(Python 3.6); the problem is, I want to isolate them as a function so I can enable the user to choose whether to reconfigure or not.
问题是,我想将它们隔离为一个功能,以便使用户能够选择是否重新配置。 (If user hasn't switched browsers nor resized, existing config file is fine.)
(如果用户没有切换浏览器或调整大小,则可以使用现有的配置文件。)
I hope a knowledgeable Pythonista can help me understand why simply indenting these lines beginning with window=Tk() four/eight spaces as appropriate and putting them in a function causes them to not run properly, instead hanging up in the middle of the first call to on_click. 我希望知识渊博的Pythonista可以帮助我理解为什么仅在适当的位置缩进以window = Tk()开头的四行/八行并将这些行放入函数中会导致它们无法正常运行,而是挂在第一次调用的中间到on_click。 (Edit: The error message from terminal is below the script)
(编辑:来自终端的错误消息在脚本下方)
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
When I try putting everything after the on_click(....) function definition into a function called map(), and then try to run map(), it hangs up after writing [tab] into the config.ini file, leaving the first window stuck on the screen. 当我尝试将on_click(....)函数定义之后的所有内容放入一个名为map()的函数中,然后尝试运行map()时,在将[tab]写入config.ini文件后,它将挂起,第一个窗口停留在屏幕上。 But when I run it as written above, it properly progresses through all three windows and writes all three parts of the config file.
但是,当我如上所述运行它时,它会在所有三个窗口中正常运行并写入配置文件的所有三个部分。 I'm sure there are terrible blunders in the script, but nevertheless: Why is it those 32 lines would run fine when out in the open, but break when they comprise a function?
我确定脚本中存在严重的错误,但是:为什么为什么这32行在开放时运行良好,而在包含函数时就中断了呢? Thanks for any help and constructive scolding!
感谢您的帮助和建设性的指责!
When you moved those lines into a function, the window
(and listener
) variables you defined stopped being global variables, and became local to that function. 当您将这些行移动到函数中时,您定义的
window
(和listener
)变量不再是全局变量,而成为该函数的局部变量。 Your on_click
functions was relying on window
(and listener
) to be defined globally, and since they no longer existed as globals at all, your code broke. 您的
on_click
函数依赖于window
(和listener
)进行全局定义,并且由于它们根本不再作为全局变量存在,因此您的代码中断了。
The minimal fix would be to add: 最小的解决方法是添加:
global window, listener
to the top of your new function, so it treats window
and listener
as global variables, rather than the default behavior of treating them as locals. 到新函数的顶部,因此它将
window
和listener
视为全局变量,而不是将它们视为局部变量的默认行为。
A more thorough solution would be to write a class where window
and listener
(and possibly other things) were instance attributes, accessed via self
, with your new function and on_click
being methods of that class. 一个更彻底的解决方案是编写一个类,其中
window
和listener
(可能还有其他东西)是实例属性,可以通过self
访问,而您的新函数和on_click
是该类的方法。 It's not critical in this case, but any time you find yourself reliant on global
for mutable global state, it's usually a bad design, and you really wanted a class in the first place. 在这种情况下并不重要,但是任何时候只要您发现自己依赖
global
变量来获取可变的全局状态,通常这都是一个糟糕的设计,并且您确实真的想在第一堂课。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.