2.33. Introspecção

Um punhado de funções embutidas permite que um programa em execução inspecione a si mesmo – os valores com que está trabalhando, os namespaces em que esses valores vivem e as relações entre as classes. Recorra a elas quando precisar tomar decisões com base no que um objeto realmente é, em vez do que seu chamador alega que ele seja.

2.33.1. Identidade e hashing

  • id() – um inteiro único que identifica um objeto enquanto ele estiver vivo. Dois nomes que vinculam o mesmo objeto retornam o mesmo id; dois objetos iguais mas distintos não.

>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b)        # same list
True
>>> id(a) == id(c)        # equal but distinct
False

O id não é portável entre execuções e não tem significado além de “mesmo objeto ou objeto diferente”.

  • hash() – o valor de hash de um objeto, o mesmo número que dict e set usam para localizá-lo. Dois objetos iguais geram o mesmo hash; apenas tipos hasheáveis (valores imutáveis, na maioria) funcionam de fato.

>>> hash("abc")           # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'

2.33.2. Consultando tipos e capacidade de chamada

  • type() – a classe exata de um valor. type(x) is int pergunta “x é exatamente um int” (sem subclasses); isinstance() normalmente é o que você quer em vez disso.

  • isinstance() – “x é uma instância desta classe, ou de uma subclasse dela?” A ferramenta padrão para despacho baseado em tipo dentro de funções.

  • issubclass() – a contraparte no nível de classe. Recebe duas classes em vez de uma instância.

  • callable()True se o argumento puder ser chamado com (). Útil quando você recebe um argumento que pode ser uma função ou pode ser um valor simples.

>>> isinstance(3, int)
True
>>> isinstance(True, int)        # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False

Um padrão que usa callable:

def call_or_return(x):
    return x() if callable(x) else x

2.33.3. Examinando escopos

  • globals() – o namespace global do módulo como um dict. Ler dele funciona; escrever nele tem efeito real, mas fazê-lo fora da exploração no REPL torna um programa difícil de acompanhar.

  • locals() – o namespace local no local da chamada. Dentro de uma função ele reflete as variáveis locais; modificar o dict retornado não tem garantia de gravar de volta nas variáveis locais reais (comportamento definido pela implementação).

name = "OpenMV"

def f():
    x = 10
    print(globals()["name"])    # OpenMV
    print(locals())             # {'x': 10}

Esses dois são úteis para depuração e para ferramentas que precisam descobrir o que está definido. Recorra a eles com parcimônia em código comum – uma função que altera globals() é uma das coisas mais difíceis de raciocinar em Python.

2.33.4. Veja também

dir() e help(), abordados em depuração, são as ferramentas de introspecção do dia a dia para explorar a superfície de um objeto desconhecido.