Python:实现一系列函数,每个函数调用下一个函数

标签 python function nameerror

编程不是我的领域,但我正在努力学习。
我一直在编写一个像这样工作的程序:

from Tkinter import *
root=Tk()

def Secondwindow():
    firstframe.destroy()
    secondframe = Frame(root)
    secondframe.pack()
    secondcontent = Label(secondframe, text = 'second window content').pack()
    def Thirdwindow():
        secondframe.destroy()
        thirdframe = Frame(root)
        thirdframe.pack()
        thirdcontent = Label(thirdframe, text = 'third window content').pack()
        def Fourthwindow():
            thirdframe.destroy()
            fourthframe = Frame(root)
            fourthframe.pack()
            fourthcontent = Label(fourthframe, text = 'fourth window content').pack()
        thirdbutton = Button(thirdframe, text = 'Next ->', command = Fourthwindow).pack()
    secondbutton = Button(secondframe, text = 'Next ->', command = Thirdwindow).pack()
firstframe = Frame(root)
firstframe.pack()
firstcontent = Label(firstframe, text = 'first window content').pack()
firstbutton = Button(firstframe, text = 'Next ->', command = Secondwindow).pack()

root.mainloop()

现在,这可以完美运行,但是随着我的程序变得更大更复杂,我开始发现这既不优雅也不易于维护。我想简单地按(或多或少)顺序编写每个函数,但是当程序读取对尚未定义的函数的引用时,这会导致名称错误(似乎程序不应该担心它,直到它必须运行该函数,到那时它已经看到了函数定义,但是哦,好吧)。

拥有此功能(从函数内部调用的函数)而不必将下一个函数定义粘贴在第一个函数定义中间的最简单方法是什么?提前致谢!

最佳答案

我取消嵌套函数以查看错误是什么。您遇到的问题是函数试图访问在另一个函数范围内定义的变量。那是行不通的。您要么必须嵌套函数,以便它们的范围重叠,就像您所做的那样——这很尴尬——或者你必须使用全局变量——这不那么尴尬,但仍然很尴尬——或者你必须从函数中传递变量名发挥作用。

但是,因为您在这里使用了回调——这是相当先进的! -- 执行第三个选项更复杂。如果你真的想让这个工作,我会建议一种面向对象的方法。但坦率地说,对于初学者来说,我建议从比这更简单的东西开始。

最重要的是你习惯了范围规则。至少,我可以用你的代码来解释。这是您得到的 NameErrors 的解释。

def Secondwindow():
    firstframe.destroy()
    secondframe = Frame(root)
    secondframe.pack()
    secondcontent = Label(secondframe, text = 'second window content').pack()
    secondbutton = Button(secondframe, text = 'Next ->', command = Thirdwindow).pack()
def Thirdwindow():
    secondframe.destroy()
    thirdframe = Frame(root)
    thirdframe.pack()
    thirdcontent = Label(thirdframe, text = 'third window content').pack()
    thirdbutton = Button(thirdframe, text = 'Next ->', command = Fourthwindow).pack()

这两个函数看起来几乎做同样的事情。但他们没有!原因如下:
def Secondwindow():
    firstframe.destroy()

此行是指firstframe ,它是在全局范围内定义的(即在程序的“最低级别”。这意味着它可以从任何地方访问。所以你在这里没问题。
    secondframe = Frame(root)
    secondframe.pack()
    secondcontent = Label(secondframe, text = 'second window content').pack()
    secondbutton = Button(secondframe, text = 'Next ->', command = Thirdwindow).pack()

这些变量都定义在Secondwindow的范围内。 .这意味着它们只存在于 Secondwindow 中。 .一旦你离开 Secondwindow ,它们不复存在。这是有充分理由的!
def Thirdwindow():
    secondframe.destroy()

现在你遇到了你的问题。这试图访问 secondframe , 但是 secondframe仅在 Secondwindow 中定义.所以你得到一个 NameError .
    thirdframe = Frame(root)
    thirdframe.pack()
    thirdcontent = Label(thirdframe, text = 'third window content').pack()
    thirdbutton = Button(thirdframe, text = 'Next ->', command = Fourthwindow).pack()

同样,这些都只在 ThirdWindow 范围内定义。 .

现在,我无法解释完成这项工作所需的所有知识,但这里有一个基本提示。您可以通过说在函数的命名空间中创建全局变量
global secondframe
secondframe = Frame(root)

通常python假设函数中定义的变量是局部变量,所以你必须告诉它否则。就是这样 global secondframe做。现在你真的不应该经常这样做,因为随着全局作用域充满了越来越多的变量,使用它们变得越来越难。函数创建更小的范围(或在某些上下文中称为“命名空间”),因此您不必跟踪所有名称(以确保您不会在两个地方使用相同的名称,或者其他更灾难性的错误)。

通常,为避免创建全局变量,您将通过调用 return secondframe 让每个函数返回它定义的帧。 .然后你可以为每个包含前一帧的函数添加一个函数参数,如 def Thirdwindow(secondframe) .但是因为你使用回调来调用 Secondwindow等,这种方法变得棘手。下面是一些使用 lambda 解决问题的代码陈述。
from Tkinter import *
root=Tk()

def Secondwindow(firstframe):
    firstframe.destroy()
    secondframe = Frame(root)
    secondframe.pack()
    secondcontent = Label(secondframe, text = 'second window content').pack()
    secondbutton = Button(secondframe, text = 'Next ->', command = lambda: Thirdwindow(secondframe)).pack()
def Thirdwindow(secondframe):
    secondframe.destroy()
    thirdframe = Frame(root)
    thirdframe.pack()
    thirdcontent = Label(thirdframe, text = 'third window content').pack()
    thirdbutton = Button(thirdframe, text = 'Next ->', command = lambda: Fourthwindow(thirdframe)).pack()
def Fourthwindow(thirdframe):
    thirdframe.destroy()
    fourthframe = Frame(root)
    fourthframe.pack()
    fourthcontent = Label(fourthframe, text = 'fourth window content').pack()

firstframe = Frame(root)
firstframe.pack()
firstcontent = Label(firstframe, text = 'first window content').pack()
firstbutton = Button(firstframe, text = 'Next ->', command = lambda: Secondwindow(firstframe)).pack()

root.mainloop()

但是解决这个问题的最好方法是使用面向对象的代码。不幸的是,这个话题太复杂了。它只会在已经很长的帖子中添加更多的措辞。老实说,我认为您应该先花一些时间来习惯函数和范围。

也就是说,我找到了一个时间来摆弄面向对象的变体。这里是:
from Tkinter import *
root=Tk()

class FrameRepeater(object):
    def __init__(self, start=0, end=4):
        self.frame = None
        self.number = start
        self.end = end

    def new_frame(self):
        if self.frame:
            self.frame.destroy()
        self.frame = Frame(root)
        self.frame.pack()
        self.content = Label(self.frame, text = 'window ' + str(self.number) + ' content')
        self.content.pack()
        self.button = Button(self.frame, text = 'Next ->', command = self.replace)
        self.button.pack()
        self.number += 1

    def replace(self):
        if self.number < self.end:
            self.new_frame()
        elif self.number >= self.end:
            self.content.config(text='Press button again to quit')
            self.button.config(command=self.quit)

    def quit(self):
        self.frame.destroy()
        root.destroy()
        exit()

FrameRepeater().new_frame()
root.mainloop()

有几点需要注意。首先,在像这样读的那些行中,有一个微妙的错误:
thirdcontent = Label(thirdframe, text = 'third window content').pack()

您正在存储 Nonethirdcontent , 因为 pack()方法没有返回值。如果您想保留对 Label 的引用,您必须先保存引用,然后 pack()分开,就像我在 new_frame 中所做的那样多于。

第二,从我的 replace 可以看出方法,您实际上不必破坏框架来更改标签或按钮命令的文本!上面仍然破坏了前三帧,只是为了展示它是如何工作的。

希望这能让你开始!祝你好运。

关于Python:实现一系列函数,每个函数调用下一个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6195790/

相关文章:

python - Timedelta 未定义

ruby-on-rails - UsersController 中的名称错误#show

python - Python 文件输出中的空格

php - mysql_fetch_array 不在函数内工作

function - Lua:冒号、 'self' 和函数定义与调用

mysql - 是否可以在 mysql 函数中声明和返回多个列?

python - 时间未定义 - python 类

python - ValueError : Dimensions must be equal, 但对于 'MatMul_1' 是 784 和 500 (op : 'MatMul' ) with input shapes: [? ,784), [500,500]

python - 如何删除 Python 中的空格?

python - 检查列表中是否不存在某个项目时,为什么此代码不起作用 - 如果列表中的项目 == False :