O que significa se um objeto Python é "subscrito" ou não?

372

Quais tipos de objetos se enquadram no domínio "subscrito"?

Alistair
fonte

Respostas:

357

Basicamente, significa que o objeto implementa o __getitem__()método. Em outras palavras, descreve objetos que são "contêineres", o que significa que eles contêm outros objetos. Isso inclui strings, listas, tuplas e dicionários.

mipadi
fonte
2
Quão confiável seria: hasattr(SomeClassWithoutGetItem, '__getitem__')determinar se algo é subscrito?
jmunsch
2
A [... ]sintaxe de indexação é chamada de subscrito , porque é equivalente a notação matemática que usa subscritos reais; por exemplo, a[1]é Python para o que os matemáticos escreveriam como a₁ . Portanto, "subscrito" significa "capaz de ser inscrito". O que, em termos do Python, significa que ele precisa ser implementado __getitem__(), já que a[1]é apenas o açúcar sintático a.__getitem__(1).
Mark Reed
Essa chamada hasattrdeve funcionar bem, mas não é a maneira pitônica de fazer as coisas; A prática de Python incentiva a digitação de pato . Ou seja, se você planeja tentar buscar um item do seu objeto usando um índice, vá em frente e faça-o; se você acha que pode não funcionar porque o objeto não é subscrito, envolva-o em um trybloco com um except TypeError.
Mark Reed
77

Em cima da minha cabeça, a seguir estão os únicos built-ins que podem ser subscritos:

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

Mas a resposta de mipadi está correta - qualquer classe que implementa __getitem__é subscrita

Dan
fonte
17

Um objeto com script é um objeto que registra as operações realizadas e pode armazená-las como um "script" que pode ser reproduzido.

Por exemplo, consulte: Application Scripting Framework

Agora, se Alistair não sabia o que ele pedia e realmente significava objetos "subscritíveis" (como editados por outros), então (como mipadi também respondeu), este é o correto:

Um objeto subscrito é qualquer objeto que implementa o __getitem__método especial (listas de reflexão, dicionários).

tzot
fonte
2
Observe que estou respondendo à pergunta original sobre objetos "programáveis", não "assináveis", conforme editados por outras pessoas, não pela Alistair. Eu realmente gostaria que Alistair comentasse.
tzot 19/10/08
Ah, um novo crachá para minha coleção! :) Brincadeirinha, obviamente. A única coisa que justificou a edição da pergunta foi que Alistair escolheu uma resposta; Ainda não tenho certeza se Alistair tinha certeza sobre a escolha.
tzot 19/10/08
17

O significado de subscrito na computação é: "um símbolo (escrito como um subscrito, mas na prática geralmente não) usado em um programa, sozinho ou com outros, para especificar um dos elementos de uma matriz".

Agora, no exemplo simples dado por @ user2194711 , podemos ver que o elemento anexado não pode fazer parte da lista por dois motivos: -

1) Não estamos realmente chamando o método append; porque precisa ()chamá-lo.

2) O erro está indicando que a função ou método não é subscrito; significa que eles não são indexáveis ​​como uma lista ou sequência.

Agora veja o seguinte: -

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

Isso significa que não há subscritos ou elementos digamos functioncomo eles ocorrem em sequências; e não podemos acessá-los como fazemos, com a ajuda de [].

Além disso; como mipadi disse em sua resposta; Basicamente, significa que o objeto implementa o __getitem__()método. (se for subscrito). Assim, o erro produzido:

arr.append["HI"]

TypeError: o objeto 'builtin_function_or_method' não é subscrito

Vicrobot
fonte
7

Eu tive esse mesmo problema. eu estava fazendo

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

Então, o uso [estava causando erro. Deveria serarr.append("HI")

user2194711
fonte
3

Como corolário das respostas anteriores aqui, muitas vezes isso é um sinal de que você acha que tem uma lista (ou ditado ou outro objeto subscrito) quando não o tem.

Por exemplo, digamos que você tenha uma função que deve retornar uma lista;

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

Agora, quando você chama essa função e, something_happens()por algum motivo, não retorna um Truevalor, o que acontece? O iffracasso, e então você cai; gimme_thingsnão explicitamente returnnada - então, de fato, implicitamente return None. Então este código:

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

falhará com " NoneTypeobjeto não é subscrito" porque, bem, thingsé Nonee você está tentando fazer o None[0]que não faz sentido, porque ... o que a mensagem de erro diz.

Há duas maneiras de corrigir esse bug no seu código - a primeira é evitar o erro, verificando se thingsé realmente válido antes de tentar usá-lo;

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 equivalentemente interceptar a TypeErrorexceção;

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

Outra é redesenhar gimme_thingspara que você sempre retorne uma lista. Nesse caso, esse é provavelmente o design mais simples, porque significa que, se houver muitos lugares onde você tem um bug semelhante, eles podem ser mantidos 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 []

Obviamente, o que você coloca na else:ramificação depende do seu caso de uso. Talvez você deva criar uma exceção quando something_happens()falhar, para torná-la mais óbvia e explícita onde algo realmente deu errado? Adicionar exceções ao seu próprio código é uma maneira importante de informar exatamente o que acontece quando algo falha!

(Observe também como essa última correção ainda não corrige completamente o erro - ela impede que você tente se inscrever, Nonemas things[0]ainda é uma lista vazia IndexErrorquando thingsestá vazia. Se você tiver uma, trypoderá fazer except (TypeError, IndexError)uma interceptação também.)

triplo
fonte