【问题标题】:nonetype object not subscriptable pysimpleguinonetype 对象不可下标
【发布时间】:2021-03-21 08:56:50
【问题描述】:

我正在尝试同时学习 python 和 pysimplegui。我也老了,没用!

我正在和我 10 岁的儿子(盲人带领盲人)编写一个练习程序,并且遇到了一个我无法解决的问题。

基本上,该程序让您输入要从中选择多少个数字以及要选择多少个数字,然后计算中奖几率。点击生成为您随机选择号码并将结果打印到 txt 文件以记录您的选择。

一切正常,但是当我关闭窗口时,我得到一个我无法解决的非类型错误。

各位天才可以帮忙吗? 这是违规行

n=int(值['--tn--'])

from os import close
import random
from tkinter import Scrollbar
import PySimpleGUI as sg
import datetime
import math
from time import sleep, time
from PySimpleGUI.PySimpleGUI import Open, WIN_CLOSED, main
import sys


sg.theme('Reddit')
layout = [
    [sg.In(size=(5,1),k="--tn--" ) ]+[sg.Text('Enter total amount of 
numbers',size=(35,1))],
    [sg.In(size=(5,1),k="--pn--")]+[sg.Text('Enter how many numbers 
you are picking',size=(35,1))],
    [sg.Text('Win odds')]+[sg.ML(background_color='light 
coral',text_color='white',key='--oddout--',size=(50,2))],
    [sg.ML(size=(20,30), key='--main--')],
    [sg.Submit('Odds',key='--odds--')]+[sg.Submit('Generate',key='-- 
gen--')]+ [sg.Cancel('Cancel')]+[sg.Save(key='--save--')]+
    [sg.CloseButton('Close',pad=(100,0))]
    ]
window = sg.Window('Lotto number generator',layout)

while True:

event, values = window.read()
n=int(values['--tn--']) 
rr=int(values['--pn--'])       
nf = math.factorial(n)
rf = math.factorial(rr)
winodds = (nf/(rf*math.factorial(n-rr)))
winodds = int(winodds)
now = datetime.datetime.now()

if event == WIN_CLOSED:
        window['--tn--'].update('1')
        break
if event == '--gen--':
    
    r = random.sample(range(1,n),rr)
    for i in r:
        window['--main--'].print(i)
        
   
if event == '--odds--':
    window['--oddout--'].print("Your chances of winning are 
",f'{winodds:,d}', " to 1, Good Luck")
if event == 'Cancel':
    window['--oddout--'].update('') 
    window['--tn--'].update('')
    window['--pn--'].update('')  
if event == '--save--':
    sys.stdout = open("lotto.txt", "w")
    print(values['--main--'])
    sys.stdout=close(fd=0)
    

window.close()

【问题讨论】:

    标签: python python-3.x pysimplegui


    【解决方案1】:

    event, values = window.read() 正在返回 NoneNone['--tn--'] 不存在,因为 None 拥有属性没有意义,因此出现错误消息。您已使用测试来避免这种情况,但将其移至尝试使用缺失属性的下方。因此出现错误。

    还值得使用 linting 工具提示您对语法进行调整,这会破坏您的代码和良好实践警告。我使用 pylint 和 flake8。以下内容通过整理 linter 消息解决了您的特定错误消息。仍然有一些警告 - 很好的学习练习:)。

    """Learning program."""
    from os import close
    import random
    import PySimpleGUI as sg
    import datetime
    import math
    from PySimpleGUI.PySimpleGUI import Open, WIN_CLOSED, main
    import sys
    
    
    sg.theme('Reddit')
    layout = [
        [sg.In(size=(5, 1), k="--tn--")] + 
        [sg.Text('Enter total amount of numbers', size=(35, 1))],
        [sg.In(size=(5, 1), k="--pn--")] +
        [sg.Text('Enter how many numbers you are picking', size=(35, 1))],
        [sg.Text('Win odds')] +
        [sg.ML(
            background_color='light coral', text_color='white', key='--oddout--', size=(50, 2)
        )],
        [sg.ML(size=(20, 30), key='--main--')],
        [sg.Submit('Odds', key='--odds--')] +
        [sg.Submit('Generate', key='--gen--')] +
        [sg.Cancel('Cancel')] +
        [sg.Save(key='--save--')] +
        [sg.CloseButton('Close', pad=(100, 0))]
        ]
    window = sg.Window('Lotto number generator', layout)
    
    while True:
        event, values = window.read()
    #    Moved the next three lines up and commented update which also errors
        if event == WIN_CLOSED:
    #        window['--tn--'].update('1')
            break
        n = int(values['--tn--']) 
        rr = int(values['--pn--'])       
        nf = math.factorial(n)
        rf = math.factorial(rr)
        winodds = (nf/(rf*math.factorial(n-rr)))
        winodds = int(winodds)
        now = datetime.datetime.now()
        if event == '--gen--':
            r = random.sample(range(1, n), rr)
            for i in r:
                window['--main--'].print(i)
        if event == '--odds--':
            window['--oddout--'].print(
                "Your chances of winning are", f'{winodds:,d}', " to 1, Good Luck"
            )
        if event == 'Cancel':
            window['--oddout--'].update('') 
            window['--tn--'].update('')
            window['--pn--'].update('')  
        if event == '--save--':
            sys.stdout = open("lotto.txt", "w")
            print(values['--main--'])
            sys.stdout = close(fd=0)
    
    
    window.close()
    

    特别是 Flake8 会提示您遵循没有明显实际目的的做法。后来随着您使用更多的语言,flake8 提示的好处是最终会带来巨大好处的好习惯。

    【讨论】:

    • 感谢 jwal 的快速回复,有很多东西可以查看。如果我们中了乐透,我们会帮你解决的...... :)
    • 如果你有时间 jwal,你能解释一下(用 5 岁的语言可以理解的语言☺),为什么 window.read() 行在移动事件之前没有返回==关闭行?
    • 您可以将变量window 视为实际的窗口。因此,例如,当您在窗口window['--tn--'] 上要求一个项目时;只有当窗口存在时才会存在。因此程序在window.read() 处暂停,直到用户采取导致事件的操作。 (它没有停顿,但这是怎么想的。)如果那甚至是关闭窗口,它就消失了,因此使用窗口查找数据是一个问题。 (它是 None,因为那个对象不见了,窗口也不见了。)这有帮助吗?
    • @nycynik 是的,这很有帮助。感谢您提供清晰的解释。
    【解决方案2】:

    有什么不好的,

    1. 你应该先检查窗口关闭事件,而不是先处理event, values其他情况,如以下代码。你可能会得到event, valuesNone, None,如果不是,那么values['--tn--'] 将与None['--tn--'] 相同。这就是你收到TypeError: 'NoneType' object is not subscriptable 的原因。
    while True:
        event, values = window.read()
        if event in (sg.WINDOW_CLOSED, 'Close'):
            break
        # process other events from here
    window.close()
    
    1. 在您的输入字段中,values['--tn--']values['--pn--'] 的整数格式可能不正确,因此以下代码可能会失败 ValueError: invalid literal for int() with base 10
    n=int(values['--tn--']) 
    rr=int(values['--pn--'])
    

    这是我避免问题的方法,

    def integer(string):
        try:
            value = int(string)
        except:
            value = None
        return value
    
    for string in ("10.5", "", "10"):
        value = integer(string)
        if value is None:
            print(f"{repr(string)} is not a legal integer string !")
        else:
            print(f"{repr(string)} converted to {value} !")
    
    '10.5' is not a legal integer string !
    '' is not a legal integer string !
    '10' converted to 10 !
    
    1. 基本上,在您单击窗口的关闭按钮X 后,窗口就会被销毁,因此您不应对其进行任何更新。
        if event == WIN_CLOSED:
            # window['--tn--'].update('1')
            break
    

    【讨论】:

    • 谢谢 Jason,我不明白你的所有建议,但我一定会去看看。你们在这里很有帮助,
    【解决方案3】:

    当您关闭窗口时,eventvalues 未设置,请参见下面的示例。

    在调试时,最好打印出eventvalues 的当前值,以便检查您是否得到了您认为应该得到的结果,如下所示:

    def test():
        layout = [[sg.In(size=(5, 1), k="--tn--"), sg.Text('Enter total amount of numbers', size=(35, 1))],
                  [sg.In(size=(5, 1), k="--pn--"), sg.Text('Enter how many numbers you are picking', size=(35, 1))],
                  [sg.Text('Win odds'),
                   sg.ML(background_color='light coral', text_color='white', key='--oddout--', size=(50, 2))],
                  [sg.ML(size=(20, 30), key='--main--')],
                  [sg.Submit('Odds', key='--odds--'), sg.Submit('Generate', key='--gen--'),
                   sg.Cancel('Cancel'), sg.Save(key=' - -save - -'), sg.CloseButton('Close', pad=(100, 0))]
                  ]
    
        window = sg.Window('Lotto number generator', layout)
    
        while True:
            event, values = window.read()
            print(f'event = {event}, values = {values}')
    
            if event == WIN_CLOSED:
                break
        window.close()
    

    当你关闭窗口时,你会得到

    event = None, values = {'--tn--': None, '--pn--': None, '--oddout--': None, '--main--': None}

    所以,用if event == WIN_CLOSED: 开始你的主循环很重要(在这种情况下打破循环)。只有在那之后,您才能继续处理各种事件和值。

    【讨论】:

    • 感谢您,我在阅读有关堆栈溢出的其他人回答有关写入 txt 文件的问题后感到困惑。他们说要在窗口关闭后打印值,我花了一些时间尝试(不成功)但以这种方式解决了。
    猜你喜欢
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 2015-01-23
    • 2022-01-12
    • 2012-01-13
    相关资源
    最近更新 更多