【问题标题】:Ensuring modules (tkinter specifically) are imported when importing classes from files从文件导入类时确保导入模块(特别是 tkinter)
【发布时间】:2014-12-16 05:31:08
【问题描述】:

我希望以 MVC 模式在其自己的文件 (view.py) 中包含以下代码。我将有一个控制器来初始化对象,然后调用 main 函数:

from view import GUI
gui = GUI()
gui.main()

然后 GUI 类确保 tkinter 被正确导入,以便它可以绘制 gui。就目前而言,尝试运行控制器代码会导致以下错误:

> python controller.py
trying to load Tkinter
loading Tkinter failed, trying tkinter instead
Loading gui
main method
Traceback (most recent call last):
  File "controller.py", line 9, in <module>
    gui.main()
  File "[...]\view.py", l
ine 31, in main
    self.root = TK.Tk()
NameError: name 'TK' is not defined

这里是 view.py:

class GUI:
    #import Tkinter # no underscore, uppercase 'T' for versions prior to V3.0
    #import tkinter # no underscore, lowercase 't' for V3.0 and later
    try:
        print("trying to load Tkinter")
        TK = __import__(Tkinter)
    except:
        print("loading Tkinter failed, trying tkinter instead")
        TK = __import__("tkinter")
    #from tkinter import N, S, E, W, END


    def __init__(self):
        print("Loading gui")

    def main(self):
        print("main method")
        # Tk root widget: window with titlebar, etc
        self.root = TK.Tk()

        # Tk buttons frame (left hand side)
        buttonsFrame = TK.Frame(self.root)
        buttonsFrame.grid(row=0, column=0, sticky=TK.N+TK.S+TK.E+TK.W)

        # Tk buttons:
        self.buttonLoad = TK.Button(buttonsFrame, text="Load Recipes", command=self.actionLoad)
        #more buttons
        self.buttonLoad.grid(row=0, column=0, sticky=TK.N+TK.S+TK.E+TK.W)
        #loading more buttons

        self.root.mainloop()


    def actionLoad(self):
        print("\"Load Recipes\" pressed")

我担心部分问题是由于缺乏对 oop 和 python 哲学的某种组合的理解,但我很高兴能同时接受这两个方面的教育。

我希望将 tkinter 作为类变量而不是作为实例变量加载会更容易解决,但这似乎没有成功。

编辑:这是更新后的 view.py 似乎运行正确

try:
    print("trying to load Tkinter")
    import Tkinter as TK
    from Tkinter import N, S, E, W, END
except ImportError:
    print("loading Tkinter failed, trying tkinter instead")
    import tkinter as TK
    from tkinter import N, S, E, W, END



class GUI:
    #import Tkinter # no underscore, uppercase 'T' for versions prior to V3.0
    #import tkinter # no underscore, lowercase 't' for V3.0 and later

    #from tkinter import N, S, E, W, END


    def __init__(self):
        print("Loading gui")

    def main(self):
        print("main method")
        # Tk root widget: window with titlebar, etc
        self.root = TK.Tk()

        # Tk buttons frame (left hand side)
        buttonsFrame = TK.Frame(self.root)
        buttonsFrame.grid(row=0, column=0, sticky=N+S+E+W)

        # Tk buttons:
        self.buttonLoad = TK.Button(buttonsFrame, text="Load Recipes", command=self.actionLoad)
        self.buttonAdd = TK.Button(buttonsFrame, text="Add Recipe", command=self.actionAdd)
        self.buttonModify = TK.Button(buttonsFrame, text="Modify Recipe", command=self.actionModify)
        self.buttonRemove = TK.Button(buttonsFrame, text="Remove Recipe", command=self.actionRemove)
        self.buttonQuit = TK.Button(buttonsFrame, text="Quit", command=self.actionQuit)
        # have to assign the layout via grid later because .grid doesn't return a type which messes up stuff like .insert()
        self.buttonLoad.grid(row=0, column=0, sticky=N+S+E+W)
        self.buttonAdd.grid(row=1, column=0, sticky=N+S+E+W)
        self.buttonModify.grid(row=2, column=0, sticky=N+S+E+W)
        self.buttonRemove.grid(row=3, column=0, sticky=N+S+E+W)
        self.buttonQuit.grid(row=4, column=0, sticky=N+S+E+W)

        # Tk recipe listbox (b/c of TK.EXTENDED, it supports selection of any combination of entries)
        self.recipeList = TK.Listbox(self.root, selectmode=TK.EXTENDED)
        # have to assign the layout via grid later because .grid doesn't return a type which messes up stuff like .insert()
        self.recipeList.grid(row=0, column=2, sticky=N+S+E+W, rowspan=10, columnspan=10)
        # populate listbox
        for option in range(0,5):
            self.recipeList.insert(TK.END, "option " + str(option))





        self.root.mainloop()

    def actionLoad(self):
        print("\"Load Recipes\" pressed")
        return "load"
    def actionAdd(self):
        print("\"Add Recipe\" pressed")
        return "add"
    def actionRemove(self):
        print("\"Remove Recipe\" pressed")
        return "remove"
    def actionModify(self):
        print("\"Modify Recipe\" pressed")
        return "modify"
    def actionQuit(self):
        quit()

【问题讨论】:

  • 为什么将代码放在类中,而不是放在包含该类的模块中?
  • 我假设如果我导入了 GUI 类并且 tkinter 导入代码不在 GUI 类中,那么在创建 GUI 类的实例时它将被忽略。
  • 你从哪里得到这样的印象?我不认为这是真的。此外,您根本不需要使用__import__。你可以直接到import Tkinter as TK 并捕获同样的错误。
  • 将它移出类定义似乎已经完成了。为什么类定义之外的代码会被执行?不应该只执行 GUI 类中的代码吗?
  • 我认为您误解了 Python 中导入的工作方式。在此站点上查找有关此的其他问题。当您执行from view import GUI 时,将执行view.py全部

标签: python tkinter


【解决方案1】:

您的原始代码抛出关于“TK”未定义的NameError 的原因是您将其导入到类(静态)变量中。因此,要使您的原始代码正常工作,可以:

  • 在变量的使用前加上类名前缀,通过在使用它的任何地方将 TK 替换为 GUI.TK(请参阅下面关于此答案的 cmets 中的讨论)。
  • 或将 try...except 块移到类之外的模块中,方法是将其放在 view.py 文件的顶部(请参阅 cmets 中有关该问题的讨论)。

但是,我认为您应该避免使用__import__(文档说“这是日常 Python 编程中不需要的高级功能”)。请尝试以下操作:

try:
    print("trying to load Tkinter")
    import Tkinter as TK
except ImportError:
    print("loading Tkinter failed, trying tkinter instead")
    import tkinter as TK

您可以像之前所做的那样将上面的块放在类中(在这种情况下,在任何地方使用GUI.TK),或者在模块中的类之外。我认为您应该将导入放在文件顶部,就像您在更新的帖子中所做的那样(PEP 8 建议“导入始终放在文件顶部”)。

还要注意ImportError 的使用。最好在此处捕获特定异常,而不是捕获所有异常(参见https://wiki.python.org/moin/HandlingExceptions 中的“常规错误捕获”部分)。

【讨论】:

  • 我实际上开始使用“import tkinter as TK”,但担心它可能无法正确分配 TK。切换回来似乎无法解决问题。
  • 显然有必要按照 BrenBarn 的建议将代码移到类定义之外。我还实现了 ImportError 以进行更精确的错误处理。谢谢!
  • @RagingRoosevelt 当然。我刚刚意识到在您的代码中,TK 是一个类(静态)变量。因此,您可以保留现有代码,并在使用 TK 的任何地方将其替换为 GUI.TK
  • @RagingRoosevelt 还有,你能编辑你的帖子在__import__(Tkinter) 中为Tkinter 添加引号吗?
  • 我切换回“import tkinter as TK”导入技术。这对使用 GUI.TK 很有意义。我将其设置为类变量(天真地)时的目标是尽量减少调用我想要的内容所需的文本量(考虑sticky = N vs sticky = GUI.TK.N)。哪种方法看起来更健壮?如果使用类变量路由更好,我想我会这样做!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-21
  • 2010-10-17
  • 1970-01-01
  • 2019-04-15
相关资源
最近更新 更多