¿Por qué obtengo “AttributeError: el objeto NoneType no tiene atributo” usando Tkinter? ¿De dónde vino el valor Ninguno?

3 minutos de lectura

Avatar de usuario de Arnkrishn
Arnkrishn

He creado esta GUI simple:

from tkinter import *

root = Tk()

def grabText(event):
    print(entryBox.get())    

entryBox = Entry(root, width=60).grid(row=2, column=1, sticky=W)

grabBtn = Button(root, text="Grab")
grabBtn.grid(row=8, column=1)
grabBtn.bind('<Button-1>', grabText)

root.mainloop()

Cuando hago clic en el Grab botón, se produce un error:

C:\Python> python.exe myFiles\testBed.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python\lib\lib-tk\Tkinter.py", line 1403, in __call__
    return self.func(*args)
  File "myFiles\testBed.py", line 10, in grabText
    if entryBox.get().strip()=="":
AttributeError: 'NoneType' object has no attribute 'get'

Por que es entryBox ajustado a None?


Consulte también ¿Por qué obtengo AttributeError: el objeto ‘NoneType’ no tiene el atributo ‘algo’? para el caso general.

  • HACER: hacer un totalmente general canonical que explica los métodos integrados y de biblioteca que devuelven None, y la decisión de diseño detrás de eso (separación de comando-consulta). Hay muchos de ellos, pero es el el mismo problema cada vez. Eso cubre el otro aspecto de este problema: stackoverflow.com/questions/8949252 cubre la comprensión del mensaje de error.

    – Karl Knechtel

    Hace 19 horas


Avatar de usuario de Cassie Meharry
cassie meharry

El grid, pack y place funciones de la Entry objeto y de todos los demás widgets devuelve None. En python cuando lo haces a().b()el resultado de la expresión es cualquiera b() vuelve, por lo tanto Entry(...).grid(...) regresará None.

Deberías dividir eso en dos líneas como esta:

entryBox = Entry(root, width=60)
entryBox.grid(row=2, column=1, sticky=W)

De esa manera obtienes tu Entry referencia almacenada en entryBox y se presenta como usted espera. Esto tiene un efecto secundario adicional de hacer que su diseño sea más fácil de entender y mantener si recopila todos sus grid y/o pack declaraciones en bloques.

  • Entonces, la codificación de una sola línea no es solo sintáctica, también tiene ramificaciones semánticas que son muy inesperadas.

    – usuario7420124

    16/03/2022 a las 19:45

  • @ user7420124, no realmente. La diferencia es lo que asignas a entryBox: en un caso es lo que Entry() vuelve, en otro es lo que grid() devoluciones.

    – Chris

    14 de agosto de 2022 a las 15:26

  • Si queremos agregar un botón final como este: tkinter.Button(root, text=”Ok”, command=lambda: [print(selection), root.destroy()]Se requiere el paquete ).pack() para agregarlo pero no es compatible con grid, ¿cómo lidiar con eso?

    – Jonathan Roy

    15 de noviembre de 2022 a las 16:44

  • Solo es inesperado si no presta atención a lo que devuelve un método. a.b.c simplemente no es lo mismo que a.bentonces a.c.

    – Chepner

    19 de noviembre de 2022 a las 16:42

Avatar de usuario de Alex Martelli
alex martelli

Cambia esta línea:

entryBox=Entry(root,width=60).grid(row=2, column=1,sticky=W)

en estas dos líneas:

entryBox=Entry(root,width=60)
entryBox.grid(row=2, column=1,sticky=W)

Tal como ya lo hace correctamente para grabBtn!

Avatar de usuario de Matiiss
matiiss

Solución alternativa para Python3.8+ versiones que permite poner todo esto en una línea usando el walrus operator:

(entryBox := Entry(root, width=60)).grid(row=2, column=1, sticky=W)

Ahora entryBox se referirá a la Entry widget y también empacar.

Para la gestión de caracteres por línea, puedo sugerir algo como esto:

(var := Button(
    text="fine", command=some_func, width=20, height=15, activebackground='grey'
)).grid(row=0, column=0, columnspan=0, rowspan=0, sticky='news')

Pero en ese momento también podría hacer esto “normalmente” (como lo sugieren otras respuestas)

Fuentes:

Para entryBox.get() acceder get() método que necesitas Entrada objeto pero Entry(root, width=60).grid(row=2, column=1, sticky=W) devuelve Ninguno.

entryBox = Entry(root, width=60) crea un nuevo objeto de entrada.

Además, no necesitarás
entryBox = entryBox.grid(row=2, column=1, sticky=W) como se reescribirá entryBox con ninguno


solo reemplaza entryBox = entryBox.grid(row=2, column=1, sticky=W)
con

entryBox = Entry(root, width=60)
entryBox.grid(row=2, column=1, sticky=W)

¿Ha sido útil esta solución?