¿Qué significa si un objeto Python es "subscriptable" o no?

Respuestas:

357

Básicamente significa que el objeto implementa el __getitem__()método. En otras palabras, describe objetos que son "contenedores", lo que significa que contienen otros objetos. Esto incluye cadenas, listas, tuplas y diccionarios.

mipadi
fuente
2
¿Qué tan confiable sería: hasattr(SomeClassWithoutGetItem, '__getitem__')determinar si una cosa es subcriptable?
jmunsch
2
El [... ]sintaxis de la indexación se llama un subíndice , porque es equivalente a la notación matemática que utiliza subíndices reales; Por ejemplo, a[1]Python es lo que los matemáticos escribirían como a₁ . Entonces "subscriptable" significa "capaz de ser subcripted". Lo cual, en términos de Python, significa que tiene que implementarse __getitem__(), ya que a[1]es solo azúcar sintáctico para a.__getitem__(1).
Mark Reed
Esa llamada a hasattrdebería funcionar bien, pero no es la forma pitónica de hacer las cosas; La práctica de Python anima a Duck Typing . Es decir, si planea intentar obtener un elemento de su objeto utilizando un subíndice, continúe y hágalo; Si cree que podría no funcionar porque el objeto no es subcriptable, envuélvalo en un trybloque con un except TypeError.
Mark Reed
77

Fuera de mi cabeza, las siguientes son las únicas incorporadas que son subscriptables:

string:  "foobar"[3] == "b"
tuple:   (1,2,3,4)[3] == 4
list:    [1,2,3,4][3] == 4
dict:    {"a":1, "b":2, "c":3}["c"] == 3

Pero la respuesta de mipadi es correcta: cualquier clase que implemente __getitem__es subscriptable

Dan
fuente
17

Un objeto programable es un objeto que registra las operaciones que se le realizan y puede almacenarlos como un "script" que puede reproducirse.

Por ejemplo, consulte: Marco de secuencias de comandos de aplicaciones

Ahora, si Alistair no sabía lo que preguntaba y realmente quería decir objetos "subscriptables" (tal como lo editaron otros), entonces (como también respondió mipadi) este es el correcto:

Un objeto subscriptable es cualquier objeto que implementa el __getitem__método especial (listas de reflexión, diccionarios).

tzot
fuente
2
Tenga en cuenta que estoy respondiendo a la pregunta original sobre los objetos "programables", no "suscribibles" tal como los han editado otros, no Alistair. Realmente me gustaría que Alistair comentara.
tzot
¡Ah, una nueva insignia para mi colección! :) Es broma, obviamente. Lo único que justificó la edición de la pregunta fue que Alistair eligió una respuesta; Todavía no estoy seguro de si Alistair estaba seguro de elegir.
tzot
17

El significado del subíndice en informática es: "un símbolo (escrito nocionalmente como subíndice pero en la práctica generalmente no) usado en un programa, solo o con otros, para especificar uno de los elementos de una matriz".

Ahora, en el ejemplo simple dado por @ user2194711 , podemos ver que el elemento adjunto no puede ser parte de la lista debido a dos razones:

1) Realmente no estamos llamando al método append; porque necesita ()llamarlo

2) El error indica que la función o método no es subscriptable; significa que no son indexables como una lista o secuencia.

Ahora mira esto: -

>>> var = "myString"
>>> def foo(): return 0
... 
>>> var[3]
't'
>>> foo[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'function' object is not subscriptable

Eso significa que no hay subíndices o dicen elementos functioncomo si ocurrieran en secuencias; y no podemos acceder a ellos como lo hacemos, con la ayuda de [].

También; como dijo mipadi en su respuesta; Básicamente significa que el objeto implementa el __getitem__()método. (si es subscriptable). Así el error producido:

arr.append["HI"]

TypeError: el objeto 'builtin_function_or_method' no es subscriptable

Vicrobot
fuente
7

Tuve el mismo problema. estaba haciendo

arr = []
arr.append["HI"]

Entonces usar [estaba causando un error. Debería serarr.append("HI")

user2194711
fuente
3

Como corolario de las respuestas anteriores aquí, muy a menudo es una señal de que crees que tienes una lista (o dict, u otro objeto suscriptable) cuando no la tienes.

Por ejemplo, supongamos que tiene una función que debería devolver una lista;

def gimme_things():
    if something_happens():
        return ['all', 'the', 'things']

Ahora, cuando llama a esa función, y something_happens()por alguna razón no devuelve un Truevalor, ¿qué sucede? El iffalla, y entonces caes; gimme_thingsno hace nada explícitamente return, entonces, de hecho, lo hará implícitamente return None. Entonces este código:

things = gimme_things()
print("My first thing is {0}".format(things[0]))

fallará con "el NoneTypeobjeto no es subscriptible" porque, bueno, sí lo thingsestá Noney está intentando hacerloNone[0] lo que no tiene sentido porque ... lo que dice el mensaje de error.

Hay dos formas de corregir este error en su código: la primera es evitar el error comprobando que thingssea ​​válido antes de intentar usarlo;

things = gimme_things()
if things:
    print("My first thing is {0}".format(things[0]))
else:
    print("No things")  # or raise an error, or do nothing, or ...

o equivalentemente atrapar la TypeErrorexcepción;

things = gimme_things()
try:
    print("My first thing is {0}".format(things[0]))
except TypeError:
    print("No things")  # or raise an error, or do nothing, or ...

Otra es rediseñar gimme_thingspara asegurarse de que siempre devuelva una lista. En este caso, ese es probablemente el diseño más simple porque significa que si hay muchos lugares donde tiene un error similar, pueden mantenerse simples e idiomáticos.

def gimme_things():
    if something_happens():
        return ['all', 'the', 'things']
    else:  # make sure we always return a list, no matter what!
        logging.info("Something didn't happen; return empty list")
        return []

Por supuesto, lo que pones en la else:rama depende de tu caso de uso. ¿Quizás debería plantear una excepción cuando something_happens()falla, para que sea más obvio y explícito dónde algo salió mal? ¡Agregar excepciones a su propio código es una forma importante de hacerse saber exactamente qué sucede cuando algo falla!

(Observe también cómo esta última solución todavía no soluciona completamente el error: evita que intente subíndice Nonepero things[0]sigue siendo un IndexErrorcuándo thingses una lista vacía. Si tiene una try, puede hacer except (TypeError, IndexError)para atraparla también).

tripleee
fuente