15. Object introspection¶
In computer programming, introspection is the ability to determine the type of an object at runtime. It is one of Python’s strengths. Everything in Python is an object and we can examine those objects. Python ships with a few built-in functions and modules to help us.
15.1. dir ¶
In this section we will learn about dir and how it facilitates us in introspection.
It is one of the most important functions for introspection. It returns a list of attributes and methods belonging to an object. Here is an example:
my_list = [1, 2, 3] dir(my_list) # Output: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', # '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', # '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', # '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', # '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', # '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', # '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', # 'remove', 'reverse', 'sort']
Our introspection gave us the names of all the methods of a list. This can be handy when you are not able to recall a method name. If we run dir() without any argument then it returns all names in the current scope.
15.2. type and id ¶
The type function returns the type of an object. For example:
print(type('')) # Output: print(type([])) # Output: print(type(<>)) # Output: print(type(dict)) # Output: print(type(3)) # Output:
id returns the unique ids of various objects. For instance:
name = "Yasoob" print(id(name)) # Output: 139972439030304
15.3. inspect module¶
The inspect module also provides several useful functions to get information about live objects. For example you can check the members of an object by running:
import inspect print(inspect.getmembers(str)) # Output: [('__add__',
There are a couple of other methods as well which help in introspection. You can explore them if you wish.
© Copyright 2017, Muhammad Yasoob Ullah Khalid Revision 9b6262ee .
Read the Docs v: latest
Versions latest Downloads pdf html epub On Read the Docs Project Home Builds Free document hosting provided by Read the Docs.
Шпаргалка по интроспекции в Python
Интроспекция — это возможность запросить тип и структуру объекта во время выполнения программы.
Встроенные функции
| Функция | Возвращаемое значение |
|---|---|
| type(obj) | тип объекта |
| dir(obj) | пространство имен объекта |
| dir() | текущее пространство имен |
| id(obj) | адрес объекта в памяти |
| help(obj) | подсказка к объекту |
| hasattr(obj, ‘attr’) | наличие атрибута у объекта |
| getattr(obj, ‘attr'[, default]) | возвращает атрибут объекта |
| locals() | словарь локальных переменных |
| globals() | словарь глобальных переменных |
Переменные
| Переменная | Значение |
|---|---|
| __annotations__ | словарь аннотаций типов |
| __name__ | имя модуля, если он импортирован, или ‘__main__’ , если запущен непосредственно. |
| __file__ | путь к файлу, содержащему объект в системе |
Модуль sys
| Функция | Возвращаемое значение |
|---|---|
| sys.argv | список аргументов, с которыми запущен интерпретатор |
| sys.executable | адрес интерпретатора в системе |
| sys.flags | флаги командной строки |
| sys.getrecursionlimit() | лимит рекурсии |
| sys.getsizeof(obj[, default]) | размер объекта |
| sys.hash_info | параметры хеширования |
| sys.modules | словарь загруженных модулей |
| sys.path | список путей для поиска модулей |
| sys.platform | операционная система |
| sys.version | версия Python |
| sys.version_info | версия Python в форме кортежа |
Практический Python для начинающих
Станьте junior Python программистом за 7 месяцев
Интроспекция в Python
Python поддерживает полную интроспекцию (отражение) времени исполнения, в том числе интроспекцию типа (type introspection (англ.) ). Это означает, что для любого объекта можно получить всю информацию о его внутренней структуре и среде исполнения. Возможности интроспекции можно условно разделить на две группы: стандартные (описанные в документации по языку (англ.) ) и нестандартные (характерные для конкретной реализации языка, например, CPython).
Примеры
Необходимые для интроспекции данные хранятся в специальных атрибутах. Так, например, получить все пользовательские атрибуты большинства объектов можно из специального атрибута — словаря (или объекта, предоставляющего dict интерфейс) __dict__
>>> class x(object):pass . >>> f = x() >>> f.attr = 12 >>> print f.__dict__ 'attr': 12> >>> print x.__dict__ # т.к. классы тоже являются экземплярами объекта type # то и они поддерживают этот тип интроспекции '__dict__': attribute '__dict__' of 'x' objects>, '__module__'.
Есть также другие атрибуты, имена и назначение которых зависят от объекта:
>>> def f():pass . >>> f.func_code.co_code # получение байтокода функции 'd\x00\x00S' >>> f.__class__ # специальный атрибут - ссылка на класс данного объекта type 'function'>
Подавляющее большинство атрибутов, поддерживающих интроспекцию, являются классовыми, и их, в свою очередь, можно получить из obj.__class__.__dict__ . Часть информации, унаследованную от базового класса, все объекты используют совместно, что позволяет экономить память.
Модуль inspect
Для удобства получения интроспективной информации в Python есть модуль inspect [1] .
>>> def f(x,y = 10,**mp):pass . >>> inspect.getargspec(f) (['x', 'y'], None, 'mp', (10,))
Модуль new
С помощью модуля new возможен обратный процесс — построения объекта из составных частей на этапе исполнения
>>> def f(i): return j + i . >>> j = 2 >>> f(1) 3 >>> import new >>> g = new.function(f.func_code, 'j': 23>) >>> g(1) 24
Примечания
Литература
- Патрик О’БрайенРуководство по интроспекции на Python / Intersoft Lab.
- David M. Beazley Python Essential Reference. — 4th Edition. — Addison-Wesley Professional, 2009. — 717 с. — ISBN 978-0672329784
- Дополнить статью (статья слишком короткая либо содержит лишь словарное определение).
- Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное.
- Проставив сноски, внести более точные указания на источники.
- Викифицировать статью.
- Концепции языков программирования
- Python
Wikimedia Foundation . 2010 .
Полезное
Смотреть что такое «Интроспекция в Python» в других словарях:
- Интроспекция в Питоне — Python поддерживает полную интроспекцию (отражение) времени исполнения, в том числе интроспекцию типа (type introspection(англ.)). Это означает, что для любого объекта можно получить всю информацию о его внутренней структуре и среде исполнения.… … Википедия
- Python — У этого термина существуют и другие значения, см. Python (значения). Python Класс языка: му … Википедия
- Интроспекция (программирование) — У этого термина существуют и другие значения, см. Интроспекция. Интроспекция (англ. type introspection) в программировании возможность в некоторых объектно ориентированных языках определить тип и структуру объекта во время выполнения… … Википедия
- Стандартная библиотека Python — Богатая стандартная библиотека является одной из привлекательных сторон языка программирования Python. Здесь имеются средства для работы со многими сетевыми протоколами и форматами интернета, например, модули для написания HTTP серверов и… … Википедия
- Пайтон — Python Класс языка: функциональный, объектно ориентированный, императивный, аспектно ориентированный Тип исполнения: интерпретация байт кода, компиляция в MSIL, компиляция в байт код Java Появился в: 1990 г … Википедия
- Интерпретируемый язык программирования — язык программирования, в котором исходный код программы не преобразовывается в машинный код для непосредственного выполнения центральным процессором (как в компилируемых языках), а исполняется с помощью специальной программы интерпретатора. В… … Википедия
- GTK+ — Тип библиотека элементов интерфейса (виджетов) Автор The GTK+ … Википедия
- Отражение (программирование) — У этого термина существуют и другие значения, см. Отражение. Для улучшения этой статьи желательно?: Перевести текст с иностранного языка на русский. Н … Википедия
- Динамическая типизация — Типизация данных Типобезопасность Вывод типов Динамическая типизация Статическая типизация Строгая типизация Мягкая типизация Зависимые типы Утиная типизация Основная статья: Строгая типизация Динамическая типизация приём, широко… … Википедия
- Objective-C — Класс языка: объектно ориентированный, мультипарадигмальный: рефлексивно ориентированный Появился в: 1986 Автор(ы): Бред Кокс Типизация данных: нестрогая, статическая / динамическая … Википедия
- Обратная связь: Техподдержка, Реклама на сайте
- Путешествия
Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.
- Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
- Искать во всех словарях
- Искать в переводах
- Искать в ИнтернетеИскать в этой же категории
Основные принципы программирования: интроспекция и рефлексия
На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.
Часто во время работы программы нам бывает нужна информация о данных — например, какой у них тип или являются ли они экземпляром класса (в ООП). Опираясь на эти знания, нам нужно проводить над данными некоторые операции, или даже изменять их — но необходимого вида данных у нас может и не быть! Если вы ничего не поняли, не расстраивайтесь — мы подробно во всём разберёмся. Всё, что я здесь описал — это иллюстрация целей двух возможностей, присутствующих почти в каждом современном языке программирования: интроспекции и рефлексии.
Интроспекция
Интроспекция — это способность программы исследовать тип или свойства объекта во время работы программы. Как мы уже упоминали, вы можете поинтересоваться, каков тип объекта, является ли он экземпляром класса. Некоторые языки даже позволяют узнать иерархию наследования объекта. Возможность интроспекции есть в таких языках, как Ruby, Java, PHP, Python, C++ и других. В целом, инстроспекция — это очень простое и очень мощное явление. Вот несколько примеров использования инстроспекции:
// Java if(obj instanceof Person)
//PHP if ($obj instanceof Person) < // делаем что угодно >
В Python самой распространённой формой интроспекции является использование метода dir для вывода списка атрибутов объекта:
# Python class foo(object): def __init__(self, val): self.x = val def bar(self): return self.x . dir(foo(5)) => ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']
В Ruby интроспекция очень полезна — в частности из-за того, как устроен сам язык. В нём всё является объектами — даже класс — и это приводит к интересным возможностям в плане наследования и рефлексии (об этом ниже). Если вы хотите узнать об этом больше, советую прочитать мини-цикл Metaprogramming in Ruby.
Прим. перев. Также не будет лишним прочитать нашу статью, посвящённую интроспекции в Ruby.
Вот несколько простых примеров интроспекции с использованием IRB (Interactive Ruby Shell):
# Ruby $ irb irb(main):001:0> A=Class.new => A irb(main):002:0> B=Class.new A => B irb(main):003:0> a=A.new => # irb(main):004:0> b=B.new => # irb(main):005:0> a.instance_of? A => true irb(main):006:0> b.instance_of? A => false irb(main):007:0> b.kind_of? A => true
Вы также можете узнать у объекта, экземпляром какого класса он является, и даже “сравнить” классы.
# Ruby irb(main):008:0> A.instance_of? Class => true irb(main):009:0> a.class => A irb(main):010:0> a.class.class => Class irb(main):011:0> A > B => true irb(main):012:0> B true
Однако интроспекция — это не рефлексия; рефлексия позволяет нам использовать ключевые принципы интроспекции и делать действительно мощные вещи с нашим кодом.
Рефлексия
Интроспекция позволяет вам изучать атрибуты объекта во время выполнения программы, а рефлексия — манипулировать ими. Рефлексия — это способность компьютерной программы изучать и модифицировать свою структуру и поведение (значения, мета-данные, свойства и функции) во время выполнения. Простым языком: она позволяет вам вызывать методы объектов, создавать новые объекты, модифицировать их, даже не зная имён интерфейсов, полей, методов во время компиляции. Из-за такой природы рефлексии её труднее реализовать в статически типизированных языках, поскольку ошибки типизации возникают во время компиляции, а не исполнения программы (подробнее об этом здесь). Тем не менее, она возможна, ведь такие языки, как Java, C# и другие допускают использование как интроспекции, так и рефлексии (но не C++, он позволяет использовать лишь интроспекцию).
По той же причине рефлексию проще реализовать в интерпретируемых языках, поскольку когда функции, объекты и другие структуры данных создаются и вызываются во время работы программы, используется какая-то система распределения памяти. Интерпретируемые языки обычно предоставляют такую систему по умолчанию, а для компилируемых понадобится дополнительный компилятор и интерпретатор, который следит за корректностью рефлексии.
Мне кажется, что мы сказали много об определении рефлексии, но смысла это пока несёт мало. Давайте взглянем на примеры кода ниже (с рефлексией и без), каждый из которых создаёт объект класса Foo и вызывает метод hello.
// ECMAScript - как JavaScript // Без рефлексии new Foo().hello() // С рефлексией // предполагаем, что Foo принадлежит this new this['Foo']()['hello']() // или не предполагаем new (eval('Foo'))()['hello']() // или вообще не заморачиваемся eval('new Foo().hello()')
// Java // Без рефлексии Foo foo = new Foo(); foo.hello(); // С рефлексией Object foo = Class.forName("complete.classpath.and.Foo").newInstance(); // Альтернатива: Object foo = Foo.class.newInstance(); Method m = foo.getClass().getDeclaredMethod("hello", new Class[0]); m.invoke(foo);
# Python # Без рефлексии obj = Foo() obj.hello() # С рефлексией class_name = "Foo" method = "hello" obj = globals()[class_name]() getattr(obj, method)() # С eval eval("Foo().hello()")
# Ruby # Без рефлексии obj = Foo.new obj.hello # С рефлексией class_name = "Foo" method = :hello obj = Kernel.const_get(class_name).new obj.send method # С eval eval "Foo.new.hello"
Этот список отнюдь не исчерпывает возможности рефлексии. Это очень мощный принцип, который к тому же является обычной практикой в метапрограммировании. Тем не менее, при использовании рефлексии нужно быть очень внимательным. Хотя у неё и есть свои преимущества, код, использующий рефлексию, значительно менее читаем, он затрудняет отладку, а также открывает двери по-настоящему плохим вещами, например, инъекции кода через выражения eval.
Eval-выражения
Некоторые рефлективные языки предоставляют возможность использования eval-выражений — выражений, которые распознают значение (обычно строку) как выражение. Такие утверждения — это самый мощный принцип рефлексии и даже метапрограммирования, но также и самый опасный, поскольку они представляют собой угрозу безопасности.
Рассмотрим следующий пример кода на Python, который принимает данные из стороннего источника в Сети (это одна из причин, по которой люди пользуются eval-выражениями):
session['authenticated'] = False data = get_data() foo = eval(data)
Защита программы будет нарушена, если кто-то передаст в метод get_data() такую строку:
"session.update(authenticated=True)"
Для безопасного использования eval-утверждений нужно сильно ограничивать формат входных данных — и обычно это лишь занимает лишнее время.
Заключение
Интроспекция и рефлексия — это очень мощные инструменты современных языков, и их понимание может позволить вам писать по-настоящему крутой код. Ещё раз отметим: интроспекция — это изучение атрибутов объекта, а рефлексия — это манипуляция ими. Будьте внимательны при использовании рефлексии, поскольку она может сделать ваш код нечитаемым и уязвимым. Чем больше сила, тем больше и ответственность — вот девиз всего, что связано с метапрограммированием.
