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, є повсякденними інструментами інтроспекції для дослідження поверхні невідомого об’єкта.