Co to znaczy, że obiekt Pythona jest „możliwy do indeksowania”, czy nie?

371

Jakie typy obiektów należą do dziedziny „podlegającej indeksacji”?

Alistair
źródło

Odpowiedzi:

356

Zasadniczo oznacza to, że obiekt implementuje __getitem__()metodę. Innymi słowy, opisuje obiekty, które są „kontenerami”, co oznacza, że ​​zawierają one inne obiekty. Obejmuje to ciągi, listy, krotki i słowniki.

mipadi
źródło
2
Jak wiarygodne byłoby: hasattr(SomeClassWithoutGetItem, '__getitem__')ustalenie, czy dana rzecz podlega indeksowi?
jmunsch
2
[... ]Składnia indeksowania jest nazywany indeks , ponieważ jest to równoznaczne z notacją matematyczną, która używa rzeczywistych indeksów; np. a[1]jest Python dla tego, co matematyk napisaliby jako a₁ . Zatem „indeksowalny” oznacza „możliwy do indeksowania”. Co, w kategoriach Python, oznacza, że ​​musi się zaimplementować __getitem__(), ponieważ a[1]jest to po prostu cukier syntaktyczny a.__getitem__(1).
Mark Reed
To wezwanie do hasattrpowinno działać dobrze, ale nie jest to Pythoński sposób robienia rzeczy; Praktyka w Pythonie zachęca do pisania kaczek . Oznacza to, że jeśli zamierzasz pobrać element ze swojego obiektu za pomocą indeksu dolnego, zrób to; jeśli uważasz, że to może nie działać, ponieważ obiekt nie podlega indeksowi, zawiń go w trybloku za pomocą except TypeError.
Mark Reed
77

Z góry mojej głowy, następujące są jedyne wbudowane, które można subskrybować:

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

Ale odpowiedź mipadi jest poprawna - każda klasa, która implementuje, __getitem__podlega indeksowi

Dan
źródło
17

Skryptowy obiekt to obiekt, który rejestruje wykonane na nim operacje i może przechowywać je jako „skrypt”, który można odtworzyć.

Na przykład zobacz: Framework skryptów aplikacji

Teraz, jeśli Alistair nie wiedział, o co pytał, i naprawdę miał na myśli obiekty „podlegające indeksacji” (edytowane przez innych), to (jak odpowiedziała również mipadi) jest to poprawny:

Obiektem do indeksowania jest każdy obiekt, który implementuje __getitem__specjalną metodę (listy myśli, słowniki).

tzot
źródło
2
Zauważ, że odpowiadam na pierwotne pytanie o obiekty „skryptowalne”, a nie „indeksowalne”, edytowane przez innych, nie Alistair. Naprawdę chciałbym, żeby Alistair skomentował.
tzot
Ach, nowa odznaka dla mojej kolekcji! :) Żartuję, oczywiście. Jedyną rzeczą, która uzasadniła redakcję pytania, było to, że Alistair wybrał odpowiedź; Nadal nie jestem pewien, czy Alistair był pewien wyboru.
tzot
16

Znaczenie indeksu dolnego w obliczeniach to: „symbol (teoretycznie zapisany jako indeks dolny, ale w praktyce zwykle nie jest) używany w programie, samodzielnie lub z innymi, w celu określenia jednego z elementów tablicy”.

Teraz w prostym przykładzie podanym przez @ user2194711 możemy zobaczyć, że element dołączający nie może być częścią listy z dwóch powodów: -

1) Tak naprawdę nie nazywamy metody append; ponieważ trzeba ()to nazwać.

2) Błąd wskazuje, że funkcja lub metoda nie podlega indeksowi; oznacza, że ​​nie można ich indeksować jak listy lub sekwencji.

Zobacz teraz: -

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

Oznacza to, że nie ma indeksów dolnych ani elementów mówionych functiontak, jakby występowały sekwencyjnie; i nie możemy uzyskać do nich dostępu tak jak my, z pomocą [].

Również; jak powiedział mipadi w swojej odpowiedzi; Zasadniczo oznacza to, że obiekt implementuje __getitem__()metodę. (jeśli można go subskrybować). W ten sposób wystąpił błąd:

arr.append["HI"]

TypeError: Obiekt „builtin_function_or_method” nie podlega indeksowi

Vicrobot
źródło
7

Miałem ten sam problem. ja robiłem

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

Używanie [powodowało błąd. Powinno byćarr.append("HI")

użytkownik2194711
źródło
3

W związku z wcześniejszymi odpowiedziami tutaj bardzo często jest to znak, że uważasz, że masz listę (lub dyktowanie, lub inny obiekt podlegający indeksacji), gdy tego nie robisz.

Załóżmy na przykład, że masz funkcję, która powinna zwrócić listę;

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

Teraz, kiedy wywołujesz tę funkcję i something_happens()z jakiegoś powodu nie zwraca Truewartości, co się dzieje? ifNie powiedzie się, a więc upadniesz poprzez; gimme_thingsnie ma returnnic jawnego - więc w rzeczywistości będzie to domyślnie niejawne return None. Następnie ten kod:

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

zakończy się niepowodzeniem, gdy „ NoneTypeobiekt nie podlega indeksowi”, ponieważ, cóż, thingsjest, Nonewięc próbujesz zrobić to, None[0]co nie ma sensu, ponieważ ... co mówi komunikat o błędzie.

Istnieją dwa sposoby naprawienia tego błędu w kodzie - pierwszy polega na uniknięciu błędu poprzez sprawdzenie, czy thingsjest poprawny przed próbą jego użycia;

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

lub równoważnie wyłapać TypeErrorwyjątek;

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

Innym jest przeprojektowanie gimme_things, aby upewnić się, że zawsze zwraca listę. W tym przypadku jest to prawdopodobnie prostsza konstrukcja, ponieważ oznacza to, że jeśli istnieje wiele miejsc, w których występuje podobny błąd, można je zachować w prosty i idiomatyczny sposób.

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

Oczywiście to, co umieścisz w else:gałęzi, zależy od przypadku użycia. Być może powinieneś poruszyć wyjątek, gdy something_happens()zawiedzie, aby uczynić go bardziej oczywistym i wyraźnym, gdy coś rzeczywiście poszło nie tak? Dodanie wyjątków do własnego kodu jest ważnym sposobem, aby dowiedzieć się dokładnie, co się dzieje, gdy coś zawiedzie!

(Zauważmy też, jak ta ostatnia poprawka jeszcze nie całkowicie naprawić błąd - to uniemożliwia próby indeksu None, ale things[0]jest nadal IndexError, gdy thingsjest pusta lista Jeśli masz. tryMożna zrobić except (TypeError, IndexError)pułapkę, too.)

potrójny
źródło