You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在search函数中访问window函数内的pokemon变量?

问题:封装Tkinter窗口函数后,回调函数无法访问内部变量

用户代码如下:

from tkinter import *
from tkinter import ttk
import requests

def window():
    root = Tk()
    root.title("Nils' Pokedex")
    
    # Styling window
    s = ttk.Style()
    s.configure('Danger.TFrame', background='red', borderwidth=5, relief='raised')
    ttk.Frame(root, width=200, height=200, style='Danger.TFrame').grid()

    mainframe = ttk.Frame(root, padding="3 3 12 12")
    mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)

    pokemon = StringVar() # Search bar Creation
    pokemon_entry = ttk.Entry(mainframe, width=7, textvariable=pokemon)
    pokemon_entry.grid(column=2, row=1, sticky=(W, E))

    ttk.Button(mainframe, text="Search", command=search).grid(column=3, row=3, sticky=W) # Search Button

    for child in mainframe.winfo_children():
        child.grid_configure(padx=5, pady=5)
    
    pokemon_entry.focus()
    root.bind("<Return>", search) # Bind 

    root.mainloop()

def search(*args):
    response = requests.get("https://pokeapi.co/api/v2/pokemon/" + str(window().pokemon)) # Fetching API
    answer = response.json()
    print(answer)

window()

问题核心:pokemon是window函数的局部变量,外部的search函数无法直接访问;且调用window()会重新创建新窗口,完全不是同一个实例的变量。


解决方案1:使用闭包(将search定义在window内部)

把search函数嵌套在window函数里,这样它就能直接访问window内的所有局部变量,不需要全局作用域:

from tkinter import *
from tkinter import ttk
import requests

def window():
    root = Tk()
    root.title("Nils' Pokedex")
    
    # Styling window
    s = ttk.Style()
    s.configure('Danger.TFrame', background='red', borderwidth=5, relief='raised')
    ttk.Frame(root, width=200, height=200, style='Danger.TFrame').grid()

    mainframe = ttk.Frame(root, padding="3 3 12 12")
    mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)

    pokemon = StringVar() # Search bar Creation
    pokemon_entry = ttk.Entry(mainframe, width=7, textvariable=pokemon)
    pokemon_entry.grid(column=2, row=1, sticky=(W, E))

    # 将search定义在window内部,形成闭包
    def search(*args):
        # 获取输入框的内容,用get()方法
        pokemon_name = pokemon.get().lower()
        if pokemon_name:
            try:
                response = requests.get(f"https://pokeapi.co/api/v2/pokemon/{pokemon_name}")
                response.raise_for_status() # 捕获HTTP错误
                answer = response.json()
                print(answer)
            except requests.exceptions.RequestException as e:
                print(f"请求出错: {e}")

    ttk.Button(mainframe, text="Search", command=search).grid(column=3, row=3, sticky=W) # Search Button

    for child in mainframe.winfo_children():
        child.grid_configure(padx=5, pady=5)
    
    pokemon_entry.focus()
    root.bind("<Return>", search) # Bind 

    root.mainloop()

window()

注意点:

  • 用pokemon.get()获取输入框的内容,而不是直接转StringVar对象
  • 增加了错误处理,避免输入无效宝可梦名称时崩溃
  • 转小写是因为PokéAPI的接口名称是小写的

解决方案2:使用类封装(更适合复杂应用)

把整个应用封装成一个类,所有组件和变量作为实例属性,回调函数作为实例方法,这种方式扩展性更强,适合后续添加更多功能:

from tkinter import *
from tkinter import ttk
import requests

class PokedexApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Nils' Pokedex")
        
        # Styling window
        s = ttk.Style()
        s.configure('Danger.TFrame', background='red', borderwidth=5, relief='raised')
        ttk.Frame(root, width=200, height=200, style='Danger.TFrame').grid()

        mainframe = ttk.Frame(root, padding="3 3 12 12")
        mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)

        self.pokemon = StringVar() # 作为实例属性
        pokemon_entry = ttk.Entry(mainframe, width=7, textvariable=self.pokemon)
        pokemon_entry.grid(column=2, row=1, sticky=(W, E))

        ttk.Button(mainframe, text="Search", command=self.search).grid(column=3, row=3, sticky=W)

        for child in mainframe.winfo_children():
            child.grid_configure(padx=5, pady=5)
        
        pokemon_entry.focus()
        root.bind("<Return>", self.search)

    def search(self, *args):
        pokemon_name = self.pokemon.get().lower()
        if pokemon_name:
            try:
                response = requests.get(f"https://pokeapi.co/api/v2/pokemon/{pokemon_name}")
                response.raise_for_status()
                answer = response.json()
                print(answer)
            except requests.exceptions.RequestException as e:
                print(f"请求出错: {e}")

if __name__ == "__main__":
    root = Tk()
    app = PokedexApp(root)
    root.mainloop()

优势:

  • 所有状态和逻辑都封装在类中,避免全局变量污染
  • 方便后续添加新功能(比如显示宝可梦图片、属性等)
  • 代码结构更清晰,维护性更强

内容的提问来源于stack exchange,提问作者Nils Edström

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 09:35:24