【问题标题】:How can this long list of variables be cleaned up?如何清理这个长长的变量列表?
【发布时间】:2020-12-29 09:04:55
【问题描述】:

在 tkinter 循环中,我有一个变量列表,用于存储用户输入的文本字符串。我在 tkinter 中使用 .get 方法将 tkinter 文本变量分配给常规 python 变量。然后我将这些变量传递给一个函数并返回它们。但它变得相当混乱。

它在技术上有效,但我想让它在眼睛上更好看。我包含了check_inputs()(这是checkInputsMaster.py 中的一个文件)来显示变量是如何传递和返回给其他函数的。所有其他功能都是这样设计的。

主要:

# obtains user inputted variables from GUI and feeds them into all other modules
folderPath,ship,flightNumber,flightDate,testNumber,missionNumber,pilot,tc,ops,missionType,etd,eta,sw,tm,gps,rdr,rtas,rswb,rmwb,lswb,lmwb,slam = check_inputs(folder_path,ship1,flight_number,flight_date,test_number,mission_number,pilot1,tc1,ops1,mission_type,etd1,eta1,sw1,var1,var2,var3,var4,var5,var6,var7,var8,var9)
flightParameters = [folderPath,ship,flightNumber,flightDate,testNumber,missionNumber,pilot,tc,ops,missionType,etd,eta,sw,tm,gps,rdr,rtas,rswb,rmwb,lswb,lmwb,slam]
# test command print(flightParameters)

# main chunk of code that creates paperwork
check_errors(*flightParameters)
logger(*flightParameters)

check_inputs() 中的checkInputsMaster.py 函数:

def check_inputs(folder_path,ship1,flight_number,flight_date,test_number,mission_number,pilot1,tc1,ops1,mission_type,etd1,eta1,sw1,var1,var2,var3,var4,var5,var6,var7,var8,var9):
    print('--------------------------\nProgram starting.\nGrabbing User Input Variables')
    global folderPath
    global ship
    global flightNumber
    global flightDate
    global testNumber
    global missionNumber
    global pilot
    global tc
    global ops
    global missionType
    global eta
    global etd
    global sw

    global tm
    global gps
    global rdr
    global rtas
    global rswb
    global rmwb
    global lswb
    global lmwb
    global slam


    folderPath=folder_path.get()
    ship=ship1.get()
    flightNumber=flight_number.get()
    flightDate=flight_date.get()
    testNumber=test_number.get()
    missionNumber=mission_number.get()
    pilot=pilot1.get()
    tc=tc1.get()
    ops=ops1.get()
    missionType=mission_type.get()
    etd=etd1.get()
    eta=eta1.get()
    sw=sw1.get()


    tm=var1.get()
    gps=var2.get()
    rdr=var3.get()
    rtas=var4.get()
    rswb=var5.get()
    rmwb=var6.get()
    lswb=var7.get()
    lmwb=var8.get()
    slam=var9.get()

    print('Variables have been grabbed')

    return(folderPath,ship,flightNumber,flightDate,testNumber,missionNumber,pilot,tc,ops,missionType,etd,eta,sw,tm,gps,rdr,rtas,rswb,rmwb,lswb,lmwb,slam)

【问题讨论】:

  • 你能试试把所有的变量都放在字典里吗?
  • 避免全局变量(或至少减少它们的数量)的常用方法是使用一些短容器(如列表和字典),或者通常更好的是,定义一个自定义类来保存(并更新)他们。
  • 你为什么将它们声明为全局并且还作为参数传递它们?这会导致代码混乱。

标签: python function tkinter


【解决方案1】:

您可以尝试将您的 GUI 包装在一个以namedtupledataclass 形式返回数据的类中,如果您正在寻找更灵活的东西。此外,如果您的 GUI 有太多元素,您可能需要考虑将其分解为更小的子 GUI。

如果您有很长的输入变量列表,您也可以查看kwargs

下面的命名元组类的简单示例。

import tkinter as tk
from collections import namedtuple

class SimpleGUI:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title('Simple GUI')

        self.var1 = tk.StringVar()
        self.var2 = tk.StringVar()

        frame = tk.Frame(self.window)
        frame.grid(sticky='nesw')

        entry = tk.Entry(frame, textvariable=self.var1)
        entry.grid(row=1, column=1, sticky='nesw')

        entry = tk.Entry(frame, textvariable=self.var2)
        entry.grid(row=1, column=2, sticky='nesw')
        
    def get_variables(self):
        Variables = namedtuple('Variables', ['var1', 'var2'])
        return Variables(self.var1.get(), self.var2.get())
>>> from simplegui import SimpleGUI
>>> gui = SimpleGUI() # Here I enter 'test1' and 'test2' into the tkinter window
>>> vars = gui.get_variables()
>>> vars
Variables(var1='test 1', var2='test 2')
>>> vars.var1
'test 1'
>>> vars.var2
'test 2'

【讨论】:

    【解决方案2】:

    确实有更好的方法来做到这一点。朝着正确方向迈出的一步是将所有信息存储在字典而不是列表中。 flightParameters 只是将您的所有数据集中在一行中,这样可以正常工作,但是字典可以让您命名其中的所有数据,而不必按数字引用每个项目。

    接下来,没有理由像这样将一堆变量传递给您的check_inputs 函数;特别是因为您立即告诉程序使用变量的全局版本;这也很奇怪,因为您将所有这些变量都返回了。我不会做任何事情,只是将您所有的.gets 存储到一个字典中,该字典返回您的主代码并保存为 flightParameters。

    第一部分的示例更改:

    # obtains user inputted variables from GUI and feeds them into all other modules
    flightParameters = check_inputs() # this will call check_inputs() and then save what it returns to flightParameters
    # test command print(flightParameters)
    
    # main chunk of code that creates paperwork
    check_errors(*flightParameters)
    logger(*flightParameters)
    

    第二部分的示例更改:

    def check_inputs():
        print('--------------------------\nProgram starting.\nGrabbing User Input Variables')
        flight_parameters = {} # empty dictionary
        
        flight_parameters['folderPath']=folder_path.get()
        flight_parameters['ship']=ship1.get()
        flight_parameters['flightNumber']=flight_number.get()
        flight_parameters['flightDate']=flight_date.get()
        flight_parameters['testNumber']=test_number.get()
        flight_parameters['missionNumber']=mission_number.get()
        flight_parameters['pilot']=pilot1.get()
        flight_parameters['tc']=tc1.get()
        flight_parameters['ops']=ops1.get()
        flight_parameters['missionType']=mission_type.get()
        flight_parameters['etd']=etd1.get()
        flight_parameters['eta']=eta1.get()
        flight_parameters['sw']=sw1.get()
    
        flight_parameters['tm']=var1.get()
        flight_parameters['gps']=var2.get()
        flight_parameters['rdr']=var3.get()
        flight_parameters['rtas']=var4.get()
        flight_parameters['rswb']=var5.get()
        flight_parameters['rmwb']=var6.get()
        flight_parameters['lswb']=var7.get()
        flight_parameters['lmwb']=var8.get()
        flight_parameters['slam']=var9.get()
    
        print('Variables have been grabbed')
    
        return flight_parameter # return the now-filled dictionary
    

    如果你这样做,那里的疯狂真的会少很多。您必须像这样访问您的数据:

    flightParameters['flightNumber']
    

    而不是这样做:

    flightParameters[2]
    

    您可能还需要考虑将所有StringVars 也保存在字典中。然后,您可以将 check_inputs 替换为以下内容:

    def check_inputs():
        print('--------------------------\nProgram starting.\nGrabbing User Input Variables')
        flight_parameters = {}
        for i in my_string_vars:
            flight_parameters[i] = my_string_vars[i].get()
        print('Variables have been grabbed')
        return(flight_parameters)
    

    【讨论】:

    • 当使用这种方法时,主要的代码块会导入checkInputs 函数。当我尝试在主要代码块中运行该函数时,我调用的函数不知道 StringVar 变量是什么/定义了它们。这些变量如何转移到不同的文件中?
    • 您可以像导入函数或类一样导入变量。 Python 就是这样。它对它们一视同仁。我不建议导入数十个变量,因为那会很混乱。将它们全部放在列表、集合或字典中,然后导入。或者,您可以将它们全部设置为类中的变量并导入该类。
    【解决方案3】:

    我绝对会为此使用dataclass。以下是我的理由:

    1. 您可以按正确的顺序分配所有变量,而不是一次一个名称
    2. 您基本上是在创建与 typedef 等效的 python,因此,它不会让您只是编造名称、拼写错误等。只允许您定义的内容。
    3. 您不必key 名称(例如:myDC['myVar'])您可以像属性一样引用它们(例如:myDC.myVar
    4. 您可以默认 dataclass 的值,只覆盖需要更改的内容。
    5. 值是严格类型的
    6. 如有必要,可轻松转换为字典
    7. 这实际上首先否定了对函数的任何需求
    8. 您可以将数据分成有意义的组,然后将它们重新组合成一个“超级组”(示例如下)

    from dataclasses import dataclass, asdict
    
    @dataclass
    class BaseSpecs:
        folderPath   :str = ''
        ship         :str = ''
        flightNumber :str = ''
        flightDate   :str = ''
        testNumber   :str = ''
    
    
    @dataclass
    class MissionSpecs:
        missionNumber :str = ''
        pilot         :str = ''
        tc            :str = ''
        ops           :str = ''
        missionType   :str = ''
        eta           :str = ''
        etd           :str = ''
        sw            :str = ''
        
    
    @dataclass
    class FlightSpecs:
        tm   :str = ''
        gps  :str = ''
        rdr  :str = ''
        rtas :str = ''
        rswb :str = ''
        rmwb :str = ''
        lswb :str = ''
        lmwb :str = ''
        slam :str = ''
        
        
    @dataclass            #order is last to first
    class FlightParameters(FlightSpecs, MissionSpecs, BaseSpecs):
        pass
    
    
    #the order is taken advantage of here.
    #no need to specifically state every property name
    flightParams = FlightParameters(
        folder_path.get(),
        ship1.get(),
        flight_number.get(),
        flight_date.get(),
        test_number.get(),
        mission_number.get(),
        pilot1.get(),
        tc1.get(),
        ops1.get(),
        mission_type.get(),
        etd1.get(),
        eta1.get(),
        sw1.get(),
        var1.get(),
        var2.get(),
        var3.get(),
        var4.get(),
        var5.get(),
        var6.get(),
        var7.get(),
        var8.get(),
        var9.get(),
    )
    
    #treated like a property instead of a key
    print(flightParams.folderPath)
    
    #easily converted to dict
    flightParamsDict = asdict(flightParams)
    

    或者,由于上述结构的原因,您也可以按以下方式进行。

    base = BaseSpecs(
        folder_path.get(),
        ship1.get(),
        flight_number.get(),
        flight_date.get(),
        test_number.get(),
    )
    
    mission = MissionSpecs(
        mission_number.get(),
        pilot1.get(),
        tc1.get(),
        ops1.get(),
        mission_type.get(),
        etd1.get(),
        eta1.get(),
        sw1.get(),
    )
    
    flight = FlightSpecs(
        var1.get(),
        var2.get(),
        var3.get(),
        var4.get(),
        var5.get(),
        var6.get(),
        var7.get(),
        var8.get(),
        var9.get(),
    )
    
    flightParams = FlightParameters(**asdict(base), **asdict(mission), **asdict(flight))
    

    【讨论】:

      猜你喜欢
      • 2015-08-15
      • 2018-09-30
      • 1970-01-01
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 2012-10-29
      相关资源
      最近更新 更多