Qu'est-ce que cela signifie si un objet Python est «indexable» ou non?

372

Quels types d'objets entrent dans le domaine des "indices"?

Alistair
la source

Réponses:

357

Cela signifie essentiellement que l'objet implémente la __getitem__()méthode. En d'autres termes, il décrit des objets qui sont des "conteneurs", ce qui signifie qu'ils contiennent d'autres objets. Cela inclut les chaînes, les listes, les tuples et les dictionnaires.

mipadi
la source
2
Quelle serait la fiabilité: hasattr(SomeClassWithoutGetItem, '__getitem__')pour déterminer si une chose est indicible?
jmunsch
2
La syntaxe d'indexation [... ]est appelée indice , car elle équivaut à la notation mathématique qui utilise des indices réels; par exemple, a[1]est Python pour ce que les mathématiciens écriraient comme a₁ . Ainsi, "souscriptible" signifie "pouvant être souscrit". Ce qui, en termes Python, signifie qu'il doit être implémenté __getitem__(), car il ne a[1]s'agit que de sucre syntaxique pour a.__getitem__(1).
Mark Reed
Cet appel à hasattrdevrait bien fonctionner, mais ce n'est pas la façon Pythonique de faire les choses; La pratique de Python encourage Duck Typing . Autrement dit, si vous prévoyez d'essayer de récupérer un élément de votre objet à l'aide d'un indice, allez-y et faites-le; si vous pensez que cela peut ne pas fonctionner parce que l'objet n'est pas indexable, enveloppez-le dans un trybloc avec un except TypeError.
Mark Reed
77

Sur le dessus de ma tête, ce qui suit sont les seuls éléments intégrés qui sont indexables:

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

Mais la réponse de mipadi est correcte - toute classe qui implémente __getitem__est indicable

Dan
la source
17

Un objet scriptable est un objet qui enregistre les opérations qui lui sont effectuées et il peut les stocker sous forme de "script" qui peut être rejoué.

Par exemple, voir: Application Scripting Framework

Maintenant, si Alistair ne savait pas ce qu'il demandait et signifiait vraiment des objets "indexables" (tels que modifiés par d'autres), alors (comme Mipadi a également répondu), c'est le bon:

Un objet indexable est tout objet qui implémente la __getitem__méthode spéciale (listes de réflexion, dictionnaires).

tzot
la source
2
Notez que je réponds à la question d'origine sur les objets "scriptables", pas "souscriptibles" tels que modifiés par d'autres, pas Alistair. J'aimerais vraiment qu'Alistair commente.
tzot
Ah, un nouveau badge pour ma collection! :) Je plaisante, évidemment. La seule chose qui justifiait la modification de la question était qu'Alistair avait choisi une réponse; Je ne sais toujours pas si Alistair était sûr de choisir.
tzot
17

La signification de l'indice dans l'informatique est: "un symbole (écrit théoriquement comme un indice mais en pratique généralement pas) utilisé dans un programme, seul ou avec d'autres, pour spécifier l'un des éléments d'un tableau."

Maintenant, dans l'exemple simple donné par @ user2194711, nous pouvons voir que l'élément ajouté ne peut pas faire partie de la liste pour deux raisons: -

1) Nous n'appelons pas vraiment la méthode append; car il doit l' ()appeler.

2) L'erreur indique que la fonction ou la méthode n'est pas indexable; signifie qu'ils ne sont pas indexables comme une liste ou une séquence.

Maintenant, voyez ceci: -

>>> 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

Cela signifie qu'il n'y a pas d'indices ou de dire des éléments functioncomme ils se produisent dans les séquences; et nous ne pouvons pas y accéder comme nous le faisons, avec l'aide de [].

Aussi; comme l'a dit mipadi dans sa réponse; Cela signifie essentiellement que l'objet implémente la __getitem__()méthode. (s'il est indexable). Ainsi l'erreur a produit:

arr.append["HI"]

TypeError: l'objet 'builtin_function_or_method' n'est pas indexable

Vicrobot
la source
7

J'ai eu ce même problème. je faisais

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

Donc, l'utilisation [provoquait une erreur. Ça devrait êtrearr.append("HI")

user2194711
la source
3

En corollaire aux réponses précédentes, il s'agit très souvent d'un signe que vous pensez avoir une liste (ou dict, ou autre objet indicable) lorsque vous n'en avez pas.

Par exemple, supposons que vous ayez une fonction qui devrait renvoyer une liste;

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

Maintenant, lorsque vous appelez cette fonction, et something_happens()pour une raison quelconque, elle ne renvoie pas de Truevaleur, que se passe-t-il? L' iféchec, et donc vous tombez; gimme_thingsne fait rien explicitement return- alors en fait, ce sera implicitement return None. Alors ce code:

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

échouera avec "l' NoneTypeobjet n'est pas indexable" parce que, eh bien, thingsc'est Noneet donc vous essayez de faire None[0]ce qui n'a pas de sens parce que ... ce que dit le message d'erreur.

Il existe deux façons de corriger ce bogue dans votre code - la première consiste à éviter l'erreur en vérifiant qu'elle thingsest en fait valide avant de tenter de l'utiliser;

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 ...

ou piéger de manière équivalente l' TypeErrorexception;

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 ...

Une autre consiste à repenser gimme_thingsafin de vous assurer qu'il renvoie toujours une liste. Dans ce cas, c'est probablement la conception la plus simple car cela signifie que s'il existe de nombreux endroits où vous avez un bug similaire, ils peuvent rester simples et idiomatiques.

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 []

Bien sûr, ce que vous mettez dans la else:branche dépend de votre cas d'utilisation. Peut-être devriez-vous lever une exception en cas d' something_happens()échec, pour rendre plus évident et explicite où quelque chose s'est mal passé? Ajouter des exceptions à votre propre code est un moyen important de vous faire savoir exactement ce qui se passe quand quelque chose échoue!

(Remarquez également que ce dernier correctif ne corrige toujours pas complètement le bogue - il vous empêche de tenter d'indexer Nonemais things[0]est toujours un IndexErrorquand thingsest une liste vide. Si vous en avez un, tryvous pouvez également le except (TypeError, IndexError)piéger.)

tripleee
la source