【问题标题】:Having trouble sending variables between functions within separate files - Python and Tkinter在单独文件中的函数之间发送变量时遇到问题 - Python 和 Tkinter
【发布时间】:2016-03-13 15:59:49
【问题描述】:

我遇到了一个看似基本的问题,但我不知道如何解决它。

我正在制作一个程序,让用户在画布上画线。我以前将整个代码放在一个文件中,但由于我要添加许多新工具,因此将所有函数隔离到单独的文件中似乎是一个明智的决定。 然而,这样做会导致问题。很抱歉有很多代码需要通过。这是我的代码:

根程序:root.py(我实际运行的那个)

#Import TKINTER toolset:
from tkinter import *
import starting_variables

#Starting variables:
starting_variables.start_vars()

#Tool width control:
global tool_width
tool_width = Scale(control_panel,from_=1,to=32)

canvas.bind("<Button-1>",line_start_xy)

control_panel.pack(side=LEFT,fill=Y)
tool_width.pack()
wrkspace.pack()
canvas.pack()

#Runs window:
window.mainloop()

这个文件从一开始就定义了所有需要的变量:(starting_variables.py)

from tkinter import *

def start_vars():
    #Starting variables:
    line_startx = 0
    line_starty = 0
    line_endx = 0
    line_endy = 0
    mouse_x = 0
    mouse_y = 0
    #Main window:
    window = Tk()
    #Workspace and Canvas:
    wrkspace =  Frame(window, bg="blue",width=640,height=480)
    canvas = Canvas(wrkspace,bg="white",width=640,height=480)
    control_panel = Frame(wrkspace,bg="white",width=32,relief=SUNKEN,bd=5)

由于某种原因,当我运行 root 程序时,它告诉我在 root.py 的第 10 行 control_panel 尚未定义,但我运行了定义它的函数。我在这里做错了什么?

【问题讨论】:

  • 当您在函数定义中声明这些变量时,它们在此类函数之外不存在。要么在定义中将每个函数声明为global,要么完全删除带有def 的行,然后在root.py 中直接以starting_variables.tool_width 访问每个变量。
  • ...或者您将return control_panel 添加到def start_vars() 的末尾,从而保留您的功能但避免使用globals(通常应该尽可能避免使用它们)。然后你可以在root.py中写ctrl_pnl = starting_variables.start_vars()ctrl_pnl.pack(side=LEFT,fill=Y)

标签: python tkinter python-3.4


【解决方案1】:

您需要了解 Python 中的作用域。您在 start_vars 函数中所做的一切对程序的其余部分都是无用的。 control_panel 仅存在于该函数的主体中。函数完成后,你没有control_panel

虽然这是一个糟糕的编程开始,你可以尝试做这样的事情:

def start_vars():
    #Starting variables:
    line_startx = 0
    line_starty = 0
    line_endx = 0
    line_endy = 0
    mouse_x = 0
    mouse_y = 0
    #Main window:
    window = Tk()
    #Workspace and Canvas:
    wrkspace =  Frame(window, bg="blue",width=640,height=480)
    canvas = Canvas(wrkspace,bg="white",width=640,height=480)
    control_panel = Frame(wrkspace,bg="white",width=32,relief=SUNKEN,bd=5)

    return locals()  # this gives a dictionary containing the local names... you don't have acces to them otherwise.

然后,在您的 root.py 中,在某个时候执行此操作

my_vars = starting_variables.start_vars()

然后你可以像这样在 root.py 中获取control_panel

control_panel = my_vars['control_panel']

只有在此之后,您才能使用 control_panel 变量。

此外,您还可以像这样进行黑客攻击

my_vars = starting_variables.start_vars()
globals().update(my_vars)

但这是一个糟糕的建议,而且你的程序结构很糟糕。

[编辑] 由于您似乎有点困惑,我会这样做:

class Application:
    # simple variables (ints, strings, etc) can be initiated here
    line_startx = 0
    line_starty = 0
    ...

    # you should have some arguments here, so as not to hard-code everything, so you can reuse this application class. For example, the widths, heights, colors maybe
    def __init__(self):  
        # In the init, put things that take a little more customization, that need parameterization, or that take longer to execute
        self.window = TK()
        self.workspace = Frame(self.window, bg="blue",width=640,height=480)
        self.canvas = Canvas(self.wrkspace, bg="white", width=640, height=480)
        self.control_panel = Frame(self.wrkspace, bg="white", width=32, relief=SUNKEN, bd=5)

这可以在您的 starting_variables.py 模块中 然后,在你的root.py,你可以放

from tkinter import *
import starting_variables

#Starting variables:
app = starting_variables.Application()  # here's where you'd pass the heights, widths, and the rest of the parameters.

#Tool width control:
tool_width = Scale(app.control_panel,from_=1,to=32)

app.canvas.bind("<Button-1>",app.line_start_xy)

app.control_panel.pack(side=LEFT,fill=Y)
tool_width.pack()
app.wrkspace.pack()
app.canvas.pack()

#Runs window:
app.window.mainloop()

我不确定您是否熟悉面向对象,但这正是我的做法。你的方式在 C 中完全可以工作,但是 Python 只是没有你期望的全局变量......一切都是模块上的属性,对象......东西。

为什么我认为我编写代码的方式更好,因为在 Python 中触摸 localsglobals 之类的函数或触摸来自其他模块的模块属性被认为是不好的,因为这是出乎意料的。人们期望函数返回值,对象保存属性和方法,类来描述对象等等......对不起,如果我用太多的理论让你感到厌烦,希望解释有所帮助:)

【讨论】:

  • 感谢您的帮助。我无法立即进行更改,但我会在完成您推荐的更改后回复您,反正我对这种事情还比较陌生哈哈。
  • 对了,你能告诉我为什么我的程序结构不好?
  • 很糟糕,只是因为你使用的这种模式显然是你自己发明的,而且我还没有找到任何项目做这样的事情。我可以继续讨论面向对象的编程,但主要思想是:您尝试做的事情称为魔术。这很神奇,因为您是唯一一个期望调用您的函数会在本地范围内创建一些变量的人。调用函数时,您应该期望返回结果而不是修改状态(除非连接到您别无选择的外部系统)。我用一个例子修改了我的答案
  • 非常感谢您的帮助,我一定会对范围进行一些研究并根据您推荐的更改采取行动。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-22
  • 1970-01-01
  • 1970-01-01
  • 2019-09-23
  • 2021-10-19
相关资源
最近更新 更多