2.33. Интроспекция

Несколько встроенных функций позволяют работающей программе исследовать саму себя – значения, с которыми она работает, пространства имён, в которых эти значения живут, и отношения между классами. Прибегайте к ним, когда нужно принимать решения на основе того, чем объект действительно является, а не того, чем его называет вызывающая сторона.

2.33.1. Идентичность и хеширование

  • id() – уникальное целое число, идентифицирующее объект всё то время, пока он жив. Два имени, связанные с одним и тем же объектом, возвращают один и тот же id; два равных, но различных объекта – нет.

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

id не переносим между запусками и не имеет смысла, кроме как «тот же объект или другой объект».

  • hash() – хеш-значение объекта, то же число, которое dict и set используют для его поиска. Два равных объекта хешируются в одно и то же значение; вообще работают только хешируемые типы (в основном неизменяемые значения).

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

2.33.2. Запрос типов и вызываемости

  • type() – точный класс значения. type(x) is int спрашивает «является ли x в точности int» (без подклассов); isinstance() обычно является тем, что вам нужно вместо этого.

  • isinstance() – «является ли x экземпляром этого класса или его подкласса?» Стандартный инструмент для диспетчеризации на основе типов внутри функций.

  • issubclass() – аналог на уровне классов. Принимает два класса, а не экземпляр.

  • callable()True, если аргумент можно вызвать с помощью (). Полезно, когда вы получаете аргумент, который может быть функцией или может быть обычным значением.

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

Шаблон, использующий callable:

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

2.33.3. Просмотр областей видимости

  • globals() – глобальное пространство имён модуля в виде dict. Чтение из него работает; запись в него реальна, но за пределами исследования в REPL это делает программу трудной для понимания.

  • locals() – локальное пространство имён в месте вызова. Внутри функции оно отражает локальные переменные; изменение возвращённого словаря не гарантированно записывается обратно в фактические локальные переменные (поведение, определяемое реализацией).

name = "OpenMV"

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

Эти две функции полезны для отладки и для инструментов, которым нужно обнаружить, что определено. Прибегайте к ним в обычном коде экономно – функция, которая изменяет globals(), относится к самым трудным для понимания вещам в Python.

2.33.4. См. также

dir() и help(), описанные в debugging, – это повседневные инструменты интроспекции для исследования поверхности незнакомого объекта.