【问题标题】:How to call function in nested function in Python如何在 Python 中调用嵌套函数中的函数
【发布时间】:2020-11-26 20:25:54
【问题描述】:

我刚开始学习编程。我正在尝试在 python 中定义一个函数,这样我就不必在我的程序中重复代码。该程序从数据库中搜索条目并显示所有条目或包含关键字的条目。这是我针对这个问题的上下文而精简的程序,它按我的意图工作:

from tkinter import *

import sqlite3
from tkinter import ttk
    

    root = Tk()
    root.title('Program')
    
    def search():
        search_window = Toplevel(root)
        search_window.title('Program - Search')
    def search_all():
        searchresult_window = Tk()
        searchresult_window.title('Program - Searchresult')

        #Checks the number of searchresults
        conn = sqlite3.connect('database.db')
        c = conn.cursor()
        c.execute('SELECT COUNT() FROM entry_table')
        number = int(str(c.fetchone()).replace(",","").replace("(","").replace(")",""));

        #Gets data from database
        c.execute('SELECT * FROM entry_table')
        data = c.fetchall()
        row_count = 0

        # Scrollbar
        main_frame = Frame(searchresult_window)
        main_frame.pack(fill=BOTH, expand=1)
        my_canvas = Canvas(main_frame)
        my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
        my_scroblbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
        my_scroblbar.pack(side=RIGHT, fill=Y)
        my_canvas.configure(yscrollcommand=my_scroblbar.set)
        my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
        seccond_frame = Frame(my_canvas)
        my_canvas.create_window((0, 0), window=seccond_frame, anchor="nw")

        # Displays searchresults on screen
        for _ in range(number):
            searchresult_frame = LabelFrame(seccond_frame, pady=5, bg='yellow1')
            searchresult_frame.pack()
            data_label = Label(hakutulos_frame, text=data[row_count][1], borderwidth=5, relief="groove", width=10)
            data_label.grid(row=0, column=0)

            row_count = row_count + 1

        c.close
        conn.close()
        search_window.destroy()
        searchresult_window.lift()

    def search_by_keyword():
        searchresult_window = Tk()
        searchresult_window.title('Program - Searchresult')

        #Checks the number of searchresults
        given_keyword = keyword.get()
        conn = sqlite3.connect('database.db')
        c = conn.cursor()
        c.execute("SELECT COUNT() FROM entry_table WHERE subject LIKE '%'||?||'%' OR header LIKE '%'||?||'%' OR entry LIKE '%'||?||'%'",
                  (given_keyword, given_keyword, given_keyword))
        number = int(str(c.fetchone()).replace(",","").replace("(","").replace(")",""));

        #Gets data from database
        c.execute("SELECT * FROM entry_table WHERE subject LIKE '%'||?||'%' OR header LIKE '%'||?||'%' OR entry LIKE '%'||?||'%'",
                  (given_keyword, given_keyword, given_keyword))
        data = c.fetchall()
        row_count = 0

        #Scrollbar
        main_frame = Frame(searchresult_window)
        main_frame.pack(fill=BOTH, expand=1)
        my_canvas = Canvas(main_frame)
        my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
        my_scroblbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
        my_scroblbar.pack(side=RIGHT, fill=Y)
        my_canvas.configure(yscrollcommand=my_scroblbar.set)
        my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
        seccond_frame = Frame(my_canvas)
        my_canvas.create_window((0,0), window=seccond_frame, anchor="nw")

        # Displays searchresults on screen
        for _ in range(number):
            searchresult_frame = LabelFrame(seccond_frame, pady=5, bg='yellow1')
            searchresult_frame.pack()
            data_label = Label(searchresult_frame, text=data[row_count][1], borderwidth=5, relief="groove", width=10)
            data_label.grid(row=0, column=0)

        c.close
        conn.close()
        search_window.destroy()
        searchresult_window.lift()

    #Show all button
    all_btn = Button(search_window, text="Show all entries", pady=5, bg='yellow1', command=search_all)
    all_btn.grid(row=0, column=0)

    #Search by keyword frame (including: entry field and search button)
    search_by_keyword_frame = LabelFrame(search_window, text="Search by keyword", pady=5, bg='yellow1')
    search_by_keyword_frame.grid(row=1, column=0)
    keyword = Entry(search_by_keyword_frame)
    keyword.delete(0, END)
    keyword.insert(END, str("Give Keyword"))
    keyword.grid(row=0, column=0)
    hae = Button(search_by_keyword_frame, text="SEARCH", pady=5, bg='yellow1', command=search_by_keyword)
    hae.grid(row=1, column=0)

    return_btn = Button(search_window, text="Return", pady=5, bg='yellow1', command =search_window.destroy)
  

      return_btn.grid(row=2, column=0, pady=5)
    
    
    search_btn = Button(root, text="Search", pady=5, bg='yellow1', command=search)
    search_btn.grid(row=2, column=0, pady=5)
    
    
    root.mainloop()

我意识到屏幕上的#Scrollbar 和#Displays 搜索结果部分是完全相同的,我想调用一个插入它的函数。然而,似乎无论我在哪里定义函数(用于滚动条和显示),我总是会出错。这是我尝试过的一个例子:

from tkinter import *
import sqlite3
from tkinter import ttk

root = Tk()
root.title('Program')

def search():
search_window = Toplevel(root)
search_window.title('Program - Search')

def function1():
    # Scrollbar
    main_frame = Frame(searchresult_window)
    main_frame.pack(fill=BOTH, expand=1)
    my_canvas = Canvas(main_frame)
    my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
    my_scroblbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
    my_scroblbar.pack(side=RIGHT, fill=Y)
    my_canvas.configure(yscrollcommand=my_scroblbar.set)
    my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
    seccond_frame = Frame(my_canvas)
    my_canvas.create_window((0, 0), window=seccond_frame, anchor="nw")

    # Displays searchresults on screen
    for _ in range(number):
        searchresult_frame = LabelFrame(seccond_frame, pady=5, bg='yellow1')
        searchresult_frame.pack()
        data_label = Label(hakutulos_frame, text=data[row_count][1], borderwidth=5, relief="groove", width=10)
        data_label.grid(row=0, column=0)

        row_count = row_count + 1

def search_all():
    searchresult_window = Tk()
    searchresult_window.title('Program - Searchresult')

    #Checks the number of searchresults
    conn = sqlite3.connect('database.db')
    c = conn.cursor()
    c.execute('SELECT COUNT() FROM entry_table')
    number = int(str(c.fetchone()).replace(",","").replace("(","").replace(")",""));

    #Gets data from database
    c.execute('SELECT * FROM entry_table')
    data = c.fetchall()
    row_count = 0

    function1()

    c.close
    conn.close()
    search_window.destroy()
    searchresult_window.lift()

def search_by_keyword():
    searchresult_window = Tk()
    searchresult_window.title('Program - Searchresult')

    #Checks the number of searchresults
    given_keyword = keyword.get()
    conn = sqlite3.connect('database.db')
    c = conn.cursor()
    c.execute("SELECT COUNT() FROM entry_table WHERE subject LIKE '%'||?||'%' OR header LIKE '%'||?||'%' OR entry LIKE '%'||?||'%'",
              (given_keyword, given_keyword, given_keyword))
    number = int(str(c.fetchone()).replace(",","").replace("(","").replace(")",""));

    #Gets data from database
    c.execute("SELECT * FROM entry_table WHERE subject LIKE '%'||?||'%' OR header LIKE '%'||?||'%' OR entry LIKE '%'||?||'%'",
              (given_keyword, given_keyword, given_keyword))
    data = c.fetchall()
    row_count = 0

    function1()

    c.close
    conn.close()
    search_window.destroy()
    searchresult_window.lift()

#Show all button
all_btn = Button(search_window, text="Show all entries", pady=5, bg='yellow1', command=search_all)
all_btn.grid(row=0, column=0)

#Search by keyword frame (including: entry field and search button)
search_by_keyword_frame = LabelFrame(search_window, text="Search by keyword", pady=5, bg='yellow1')
search_by_keyword_frame.grid(row=1, column=0)
keyword = Entry(search_by_keyword_frame)
keyword.delete(0, END)
keyword.i

nsert(END, str("Give Keyword"))
    keyword.grid(row=0, column=0)
    hae = Button(search_by_keyword_frame, text="SEARCH", pady=5, bg='yellow1', command=search_by_keyword)
    hae.grid(row=1, column=0)

    return_btn = Button(search_window, text="Return", pady=5, bg='yellow1', command =search_window.destroy)
    return_btn.grid(row=2, column=0, pady=5)


search_btn = Button(root, text="Search", pady=5, bg='yellow1', command=search)
search_btn.grid(row=2, column=0, pady=5)


root.mainloop()

【问题讨论】:

  • 您能发布您遇到的错误吗?
  • 这是错误:Tkinter 回调回溯中的异常(最近一次调用最后一次):文件“C:\Users\Name\AppData\Local\Programs\Python\Python38-32\lib\tkinter_init_.py”,第 1883 行,在 call 中返回 self.func(*args) 文件“C:/Users/Name/PycharmProjects/test/venv/Testi.py” ,第 49 行,在 search_all function1() 文件“C:/Users/Name/PycharmProjects/test/Testi.py”,第 14 行,在 function1 main_frame = Frame(searchresult_window) NameError: name 'searchresult_window' is not defined
  • 请提供minimal reproducible example,以及整个错误输出。

标签: python tkinter methods nested


【解决方案1】:

这是您的错误输出:

Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\Name\AppData\Local\Programs\Python\Python38-32\lib\tkinter_init_.py", line 1883, in call return self.func(*args) File "C:/Users/Name/PycharmProjects/test/venv/Testi.py", line 49, in search_all function1() File "C:/Users/Name/PycharmProjects/test/Testi.py", line 14, in function1 main_frame = Frame(searchresult_window) NameError: name 'searchresult_window' is not defined

解释器抱怨的根本错误是这样的:

line 14, in function1 main_frame = Frame(searchresult_window) NameError: name 'searchresult_window' is not defined

意思是,Python 解释器找不到变量 searchresult_window 来在 function1 中使用它,因为它不在 function1 的范围内。您已经在其他函数 (search_all) 中定义了变量,但没有将其传递给 function1。您应该将变量传递给 function1 或在 function1 可以访问它的范围内定义变量。我在全局范围内定义了变量,这应该可以解决问题。

searchresult_window = Tk()
searchresult_window.title('Program - Searchresult')

def function1():
    # Scrollbar
    main_frame = Frame(searchresult_window)
    main_frame.pack(fill=BOTH, expand=1)
    my_canvas = Canvas(main_frame)
    my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
    my_scroblbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
    my_scroblbar.pack(side=RIGHT, fill=Y)
    my_canvas.configure(yscrollcommand=my_scroblbar.set)
    my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
    seccond_frame = Frame(my_canvas)
    my_canvas.create_window((0, 0), window=seccond_frame, anchor="nw")

    # Displays searchresults on screen
    for _ in range(number):
        searchresult_frame = LabelFrame(seccond_frame, pady=5, bg='yellow1')
        searchresult_frame.pack()
        data_label = Label(hakutulos_frame, text=data[row_count][1], borderwidth=5, relief="groove", width=10)
        data_label.grid(row=0, column=0)

        row_count = row_count + 1

def search_all():    
    #Checks the number of searchresults
    conn = sqlite3.connect('database.db')
    c = conn.cursor()
    c.execute('SELECT COUNT() FROM entry_table')
    number = int(str(c.fetchone()).replace(",","").replace("(","").replace(")",""));

    #Gets data from database
    c.execute('SELECT * FROM entry_table')
    data = c.fetchall()
    row_count = 0

    function1()

    c.close
    conn.close()
    search_window.destroy()
    searchresult_window.lift()

【讨论】:

  • "我在全局范围内定义了变量,这应该可以解决问题。"我很难理解你所指的女巫变量,因为 function1 中有很多变量(main_frame、my_canvas、我的滚动条等)。我想我理解范围界定背后的想法,但也许这是我不明白的一些特定机制。对不起,我认为我有语言障碍,没有上下文就无法理解。
  • 搜索结果窗口。这就是你得到错误的变量。
  • 非常感谢!这个问题比我理解的要复杂得多,但我让它在我的原始程序上运行。在这个问题的上下文中,它是关于将多个变量传递给 function1 (searchresult_window, number, row_count, data)。我很难弄清楚,因为在我的程序中number 是由这个例子中的数据库女巫定义的,和平中什么都没有。同样在我的主程序上,我还有更多的变量要传递给函数。非常感谢!
  • 当然。您也可以像以前一样传递变量。我觉得 searchresult_window 属于全局范围,因为您将它定义在一个函数中并被另一个函数使用;认为多个功能需要访问它。很高兴你把它整理出来。
【解决方案2】:

让我们使用您的示例/问题并解释有关 Python 的两个选项。

问题是您在方法 search() 中创建了 search_window,因此它只在其中定义。

Python 作为一种编程语言为您提供了许多选择(就像任何其他编程语言一样)

选项 1:使用 return

您可以从方法中返回变量,然后在其他位置使用它

def search():
    search_window = Toplevel(root)
    search_window.title('Program - Search')
    return search_window  # i added this line at the end of the function

稍后在代码中你可以这样做:

    search_window = search()

选项 2:全局关键字

Python 使您能够从方法内部更新(或定义)全局变量。

def search():
    global search_window # added ths line to define global variable
    search_window = Toplevel(root)
    search_window.title('Program - Search')

不要忘记在下面的某处调用 search()(在您的示例中您不会这样做)。 从那时起,您将拥有一个名为 search_window 的新变量。简单地接近它。

【讨论】:

  • 这并没有解决我在这个特定程序上的问题,但我现在已经了解了返回和范围。我非常感谢您的意见!总的来说,它对我有帮助。
  • 如果您对我的评论投赞成票,我将不胜感激。谢谢@Heikki。
  • 如果可以的话,我会的。看来我在 Stack Overflow 上还没有这样做的声誉,但当我这样做时,我会尽量记住这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-13
  • 2021-08-19
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多