Многие языки программирования поддерживают интроспекцию, и Python не является исключением. В общем, в контексте объектно-ориентированных языков программирования, интроспекция — это способность объекта во время выполнения получить тип, доступные атрибуты и методы, а также другую информацию, необходимую для выполнения дополнительных операций с объектом.

В этой статье мы рассмотрим пять самых полезных функций интроспекции в Python.


dir()

Первая функция — это функция dir(). Она предоставляет список атрибутов и методов, доступных для указанного объекта, который может быть объявленной переменной или функцией.

>>> a = [1, 2, 3]
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

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

>>> b = [1, 2, 3]
>>> b_dir = dir(b)
>>> 'index' in b_dir
True
>>> 'pop' in b_dir
True

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

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b', 'b_dir']

type()

Другой часто используемой функцией интроспекции является функция type(). Как видно из названия, эта функция возвращает тип объекта, который может быть примитивным типом данных, объектом, классом или модулем. Давайте посмотрим на примеры ниже:

>>> type(1.2)
<class 'float'>
>>> type([1, 2, 3])
<class 'list'>
>>> type((3, 'Three'))
<class 'tuple'>
>>> def do_something():
... pass
... 
>>> type(do_something)
<class 'function'>
>>> class Fruit:
... pass
... 
>>> type(Fruit)
<class 'type'>
>>> type(Fruit())
<class '__main__.Fruit'>
>>> import os
>>> type(os)
<class 'module'>

Что мы можем сделать с возвращаемыми значениями из функции type()? Мы можем напрямую сравнить возвращаемое значение с типом, который мы хотим проверить, используя == или is. Ниже приведено несколько примеров.

>>> type(1.2) == int
False
>>> type(1.2) == float
True
>>> type([1,2]) == list
True
>>> type((1,2)) is tuple
True

isinstance()

Еще одной из функций интроспекции, которая особенно полезна, является функция isinstance(). Используя эту функцию, мы можем определить, является ли определенный объект экземпляром указанного класса. Простой пример приведен ниже.

>>> isinstance([1,2], list)
True
>>> isinstance([1,2], tuple)
False
>>> isinstance((1,2), tuple)
True

Следует также отметить, что функция isinstance() может принимать кортеж в качестве второго аргумента, как показано ниже.

>>> isinstance(1, (int, float, tuple))
True
>>> isinstance(1, int) or isinstance(1, float) or isinstance(1, tuple)

Рассмотрим более практический пример использования, который включает в себя пользовательский класс:

>>> class Fruit:
... pass
... 
>>> apple = Fruit()
>>> isinstance(apple, Fruit)
True

Возможно, вы заметили, что и type(), и isinstance() могут быть использованы для определения того, принадлежит ли указанный объект определенному типу. Тем не менее, они не одинаковы.

Когда мы используем type(), чтобы определить, принадлежит ли объект определенному типу, мы проводим сравнение один к одному. По сути, мы сравниваем тип объекта с типом, который мы указали, чтобы проверить, совпадают ли они.

А вот isinstance() является более гибкой функцией. Фактически она определяет, является ли объект экземпляром указанного класса (классов) или его подкласса.  Для isinstance() экземпляр подкласса также является экземпляром базового класса. Другими словами, она сравнивает объект со списком потенциально релевантных классов, что является своего рода сравнением один к нескольким. На рисунке ниже приведен пример работы функции.


hasattr()

Иногда, прежде чем получить доступ к атрибуту объекта, мы можем захотеть проверить, есть ли у него этот атрибут. Мы не хотим видеть следующую ошибку:

>>> class Fruit:
... pass
... 
>>> Fruit().tasty
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Fruit' object has no attribute 'tasty'

Чтобы подобного не произошло, мы можем с помощью функции hasattr() проверить, есть ли у объекта такой атрибут, прежде чем обращаться к нему.

>>> class Fruit:
... tasty = True
... 
>>> fruit = Fruit()
>>> if hasattr(fruit, 'tasty'):
... print('The fruit is tasty')
... else:
... print('The fruit is not tasty')
... 
The fruit is tasty

Возможно, вы не обратили на это внимание, но мы можем использовать функцию dir() для достижения того же самого результата.

Как вы помните, функция dir() возвращает доступные атрибуты и методы для указанного объекта, так что мы можем напрямую сравнить, является ли атрибут одним из элементов возвращаемого списка. Ниже приведен обновленный код.

>>> class Fruit:
... tasty = True
... 
>>> fruit = Fruit()
>>> if 'tasty' in dir(fruit):
... print('The fruit is tasty')
... else:
... print('The fruit is not tasty')
... 
The fruit is tasty

id()

И последняя, но не менее важная функция интроспекции в Python — это функция id(). Она возвращает идентификатор указанного объекта. В CPython идентификатор объекта — это адрес объекта в памяти, который является уникальным для всех существующих объектов. Объекты могут иметь одинаковый идентификатор, если периоды их существования не пересекаются. Ниже приведен простой пример этой функции.

a = 2
b = 1
id(a)
140339209865072
id(b)
140339209865096

Один из распространенных примеров кода в Python — это обмен значений двух переменных. Этого можно добиться, просто выполнив следующий код a, b = b, a. Давайте посмотрим, что происходит после обмена.

id(a)
140339209865096
id(b)
140339209865072
a, b
(1, 2)

Как мы можем заметить, эти две переменные успешно поменялись местами, что видно из их адресов в памяти и значений.


Выводы

Проводить интроспекцию в Python очень удобно.

Если вы хотите узнать о более продвинутых  методах интроспекции в Python, то можете изучить модуль inspect.

Пять функций, которые были рассмотрены в этой статье, являются наиболее распространенными. Вы смело можете использовать их в своих проектах на Python.

Alina_selina

Recent Posts

7 наилучших библиотек визуализации Python на 2024 год

Python предлагает набор библиотек, удовлетворяющих различные потребности в визуализации, будь то академические исследования, бизнес-аналитика или…

2 дня ago

Как преобразовать строку в байты в Python

В Python для представления данных в двоичной форме можно использовать байты. Из этой статьи вы…

2 недели ago

Что такое Werkzeug?

В этой статье рассказывается о том, что такое Werkzeug и как Flask использует его для…

2 недели ago

Как прибавить дни, месяцы и годы к дате в Python

При работе с датами часто возникает необходимость прибавлять к дате или вычитать из нее различные…

3 недели ago

Социальная аутентификация в приложении на Flask

В этом руководстве мы рассмотрим, как добавить социальную аутентификацию с помощью GitHub и Google в…

1 месяц ago

Проверка типов в Python

В этой статье мы рассмотрим, что такое подсказки типов и чем они могут быть полезны.…

1 месяц ago