Содержание статьи

При работе с объектно-ориентированным кодом в Python разработчик регулярно сталкивается с задачей анализа уже существующих классов. Это может быть сторонняя библиотека, встроенный тип или собственный класс, написанный ранее. Понимание того, какие методы доступны у класса, напрямую влияет на корректное использование его интерфейса и предотвращает ошибки, связанные с вызовом несуществующих или неподходящих методов.
Python предоставляет несколько встроенных инструментов для получения списка методов класса: от базовых функций языка до специализированных модулей стандартной библиотеки. Каждый из них решает свою задачу – один показывает все атрибуты без исключений, другой позволяет отделить методы от свойств, третий помогает определить, какие методы были унаследованы, а какие объявлены непосредственно в классе.
Важно учитывать различия между методами экземпляра, методами класса и статическими методами, а также понимать, как Python хранит их внутри объекта. Без этого легко перепутать служебные атрибуты, магические методы и пользовательскую логику. В статье рассматриваются практические способы просмотра методов с пояснением, когда и какой подход стоит применять.
Отдельное внимание уделяется модулю inspect, который позволяет получать структурированную информацию о классе и его методах, включая сигнатуры функций и источник определения. Такой подход особенно полезен при отладке, рефакторинге и изучении сложных иерархий наследования.
Все примеры ориентированы на реальное использование в коде и подходят как для анализа встроенных типов Python, так и для пользовательских классов. Материал рассчитан на разработчиков, которые хотят глубже разобраться в устройстве классов и осознанно работать с их методами.
Получение списка методов класса с помощью функции dir()
Функция dir() – базовый инструмент Python для получения полного списка атрибутов объекта, включая методы класса. При передаче класса в dir() возвращается отсортированный список строк, содержащий имена всех доступных атрибутов: пользовательские методы, унаследованные методы, магические методы и свойства.
Простейший способ просмотра методов выглядит так:
class Example:
def foo(self):
pass
def bar(self):
pass
print(dir(Example))
Результат будет включать не только foo и bar, но и служебные методы, такие как __init__, __dict__, __module__ и другие. Это важно учитывать: dir() не фильтрует данные и показывает всё, что доступно через механизм атрибутов.
Для анализа методов экземпляра вместо класса можно передать объект:
instance = Example()
print(dir(instance))
В этом случае список будет шире, так как Python добавит атрибуты, доступные через экземпляр. Такой подход полезен для проверки того, какие методы реально доступны при работе с объектом, а не только объявлены в классе.
dir() удобно использовать для первичного обзора структуры класса, отладки и быстрого изучения незнакомых объектов. Для более точного выделения методов из полученного списка требуется дополнительная фильтрация, так как функция не различает методы, свойства и обычные атрибуты.
Фильтрация методов класса из результата dir()

Пример базовой фильтрации методов класса:
class Example:
value = 10
def foo(self):
pass
def bar(self):
pass
methods = [
name for name in dir(Example)
if callable(getattr(Example, name))
]
print(methods)
В полученном списке будут как пользовательские методы, так и магические методы Python. Чтобы исключить служебные элементы, обычно отфильтровывают имена, начинающиеся и заканчивающиеся двойным подчёркиванием.
Пример фильтрации только пользовательских методов:
methods = [
name for name in dir(Example)
if callable(getattr(Example, name)) and not name.startswith("__")
]
Такой подход позволяет быстро выделить рабочий интерфейс класса без лишнего шума. Однако он не отличает методы класса от статических методов и методов экземпляра – все они будут представлены как вызываемые атрибуты.
Типы элементов, которые могут присутствовать в результате фильтрации, показаны ниже:
| Тип атрибута | Попадает в dir() | Проходит callable() |
|---|---|---|
| Метод экземпляра | Да | Да |
| Статический метод | Да | Да |
| Метод класса | Да | Да |
| Свойство (property) | Да | Нет |
| Обычный атрибут | Да | Нет |
Фильтрация через callable() остаётся самым простым способом извлечения методов из результата dir(). Для более точного анализа, включая сигнатуры и источник определения, применяются инструменты из модуля inspect.
Просмотр только публичных методов класса

Публичными методами в Python считаются методы, имена которых не начинаются с подчёркивания. Такой интерфейс предназначен для прямого использования и именно его обычно изучают при работе с новым классом. Для получения списка публичных методов используется сочетание dir(), getattr() и проверки имени.
Базовый алгоритм фильтрации включает несколько шагов:
- получить все имена атрибутов через dir(Класс);
- исключить элементы с ведущим символом _;
- оставить только вызываемые атрибуты.
Пример реализации:
class Example:
def foo(self):
pass
def _internal(self):
pass
def bar(self):
pass
public_methods = [
name for name in dir(Example)
if not name.startswith("_")
and callable(getattr(Example, name))
]
print(public_methods)
Результат будет содержать только foo и bar. Методы с одним подчёркиванием используются для внутренней логики, а методы с двойным подчёркиванием относятся к протоколам Python и не рассматриваются как часть внешнего API.
При анализе публичных методов полезно учитывать:
- статические и классовые методы также считаются публичными, если не начинаются с подчёркивания;
- методы, унаследованные от базовых классов, будут включены в список;
- свойства с декоратором @property не попадут в результат из-за отсутствия признака вызываемости.
Такой способ позволяет быстро получить актуальный список методов, предназначенных для работы с классом, без изучения внутренней реализации и служебных механизмов.
Определение методов экземпляра через объект класса
Просмотр методов через экземпляр класса позволяет увидеть именно тот набор методов, который доступен при работе с объектом во время выполнения программы. В отличие от анализа самого класса, такой подход учитывает механизм привязки методов и особенности разрешения атрибутов.
Для начала создаётся экземпляр класса, после чего к нему применяется функция dir():
class Example:
def foo(self):
pass
def bar(self):
pass
obj = Example()
print(dir(obj))
Полученный список будет включать имена методов класса, унаследованные методы, а также атрибуты, добавленные экземпляру динамически. Ключевое отличие состоит в том, что методы экземпляра представлены как bound methods, то есть уже привязанные к конкретному объекту.
Для выделения методов экземпляра применяется фильтрация по вызываемости:
instance_methods = [
name for name in dir(obj)
if callable(getattr(obj, name))
]
Такой список отражает реальные возможности объекта: если метод переопределён в подклассе или добавлен через присваивание функции атрибуту экземпляра, он будет присутствовать в результате.
Анализ через экземпляр полезен в следующих случаях:
- проверка методов объектов, создаваемых фабричными функциями;
- отладка поведения классов с динамическим добавлением атрибутов;
- изучение интерфейса объектов, возвращаемых сторонними библиотеками.
Использование экземпляра вместо класса даёт более точное представление о доступных методах в конкретной точке выполнения программы.
Использование модуля inspect для анализа методов класса

Модуль inspect из стандартной библиотеки Python предоставляет инструменты для детального анализа структуры классов. В отличие от dir(), он позволяет работать не только с именами методов, но и с их типами, сигнатурами и источником определения.
Для получения методов класса чаще всего используется функция inspect.getmembers() в сочетании с предикатами:
import inspect
class Example:
def foo(self):
pass
@classmethod
def bar(cls):
pass
methods = inspect.getmembers(Example, predicate=inspect.isfunction)
print(methods)
Такой вызов вернёт список кортежей, где каждый элемент содержит имя метода и сам объект функции. Важно учитывать, что inspect.isfunction находит только функции, объявленные в теле класса, и не включает унаследованные методы.
Для более полного анализа применяются разные предикаты:
- inspect.isfunction – методы, объявленные в классе;
- inspect.ismethod – методы, привязанные к экземпляру;
- inspect.isbuiltin – встроенные методы, реализованные на C.
Пример получения всех методов, включая унаследованные:
methods = inspect.getmembers(Example, callable)
Модуль inspect также позволяет извлекать сигнатуры методов, что полезно при анализе API:
for name, method in inspect.getmembers(Example, inspect.isfunction):
print(name, inspect.signature(method))
Использование inspect оправдано в ситуациях, где требуется:
- отделить собственные методы класса от унаследованных;
- понять, какие аргументы принимает каждый метод;
- анализировать сложные иерархии классов без чтения исходного кода.
Этот инструмент особенно полезен при разработке фреймворков, автодокументации и систем динамического вызова методов.
Получение методов, объявленных непосредственно в классе
Чтобы получить только те методы, которые объявлены в самом классе, а не унаследованы, следует работать с пространством имён класса. Ключевой источник информации – атрибут __dict__, содержащий все объекты, определённые непосредственно в теле класса.
Базовый подход – отфильтровать элементы cls.__dict__, оставив только вызываемые объекты функций. Это позволяет исключить методы родительских классов и автоматически игнорирует магию MRO.
class MyClass:
def a(self): pass
@classmethod
def b(cls): pass
@staticmethod
def c(): pass
methods = [
name for name, obj in MyClass.dict.items()
if callable(obj)
]
Такой способ вернёт a, b и c, но не включит методы, унаследованные от object. В отличие от dir(), здесь отсутствует шум из стандартных атрибутов.
Если требуется строго разделить типы методов, необходимо учитывать их обёртки. classmethod и staticmethod не являются функциями напрямую, поэтому для точной идентификации используется проверка типов.
import inspect
instance_methods = [
name for name, obj in MyClass.dict.items()
if inspect.isfunction(obj)
]
Этот вариант вернёт только обычные методы экземпляра, исключив статические и классовые методы. Для выборки классовых методов используется проверка isinstance(obj, classmethod), а для статических – isinstance(obj, staticmethod).
Использование inspect.getmembers() оправдано только при дополнительной фильтрации по __qualname__ или __module__. Без этого оно возвращает унаследованные элементы, что противоречит задаче.
Оптимальная стратегия для анализа структуры класса – начинать с __dict__ и добавлять проверки типов только при необходимости. Это минимизирует вычислительные затраты и даёт предсказуемый результат.
Просмотр унаследованных методов класса
Для анализа унаследованных методов необходимо учитывать порядок разрешения методов (MRO). Python определяет его через атрибут __mro__, который содержит кортеж всех классов, участвующих в наследовании, начиная с текущего.
Простейший способ увидеть все доступные методы, включая унаследованные, – использовать dir(). Однако этот результат содержит служебные и магические элементы, поэтому его следует рассматривать только как отправную точку.
class Child(Parent):
pass
methods = dir(Child)
Для получения именно унаследованных методов требуется исключить элементы, объявленные в самом классе. Это достигается сравнением атрибутов __dict__ дочернего и родительских классов.
inherited = set()
for base in Child.__mro__[1:]:
inherited.update(base.__dict__.keys())
own = set(Child.dict.keys())
inherited_methods = [
name for name in inherited - own
if callable(getattr(Child, name, None))
]
Такой подход позволяет точно определить методы, пришедшие из каждого базового класса, включая методы, определённые в object, если это необходимо для анализа.
Для более детальной фильтрации рекомендуется использовать модуль inspect. Он позволяет исключить свойства, дескрипторы и другие вызываемые объекты, не являющиеся методами.
import inspect
inherited_methods = [
name for cls in Child.mro[1:]
for name, obj in cls.dict.items()
if inspect.isfunction(obj)
]
Этот вариант возвращает только методы экземпляра, унаследованные от базовых классов, и игнорирует переопределённые методы, так как они присутствуют в __dict__ дочернего класса.
Использование MRO гарантирует корректную обработку множественного наследования и предотвращает дублирование методов, что критично при анализе сложных иерархий классов.
Отличие методов класса от атрибутов и свойств

При просмотре методов класса важно корректно отделять их от атрибутов данных и свойств. В пространстве имён класса все эти элементы представлены как объекты, но их семантика и поведение принципиально различаются.
Метод класса – это функция, определённая в теле класса и реализующая протокол дескриптора. При обращении через экземпляр она автоматически привязывается к объекту. В __dict__ класса такие элементы представлены как объекты типа function, classmethod или staticmethod.
import inspect
methods = [
name for name, obj in MyClass.dict.items()
if inspect.isfunction(obj)
]
Обычные атрибуты данных не являются вызываемыми объектами и не участвуют в механизме связывания. Они могут быть любого типа: числа, строки, коллекции. Проверка через callable() надёжно исключает их из списка методов.
Свойства (property) представляют собой дескрипторы, маскирующиеся под атрибуты. Несмотря на наличие исполняемого кода, они не считаются методами, так как вызываются без скобок и возвращают значение.
properties = [
name for name, obj in MyClass.__dict__.items()
if isinstance(obj, property)
]
При использовании inspect.getmembers() без фильтрации свойства и методы часто смешиваются, так как оба типа могут быть вызываемыми после привязки. Для точного разделения следует анализировать объект до доступа через экземпляр.
Рекомендуемый порядок фильтрации: сначала исключать свойства по типу property, затем проверять inspect.isfunction() для методов экземпляра и отдельно обрабатывать classmethod и staticmethod.
Такой подход обеспечивает корректный список методов класса без ложных срабатываний на вычисляемые атрибуты и пользовательские дескрипторы.
Вопрос-ответ:
Почему dir() показывает так много методов, которых нет в моём классе?
Функция dir() возвращает полный набор атрибутов, доступных объекту, включая методы всех базовых классов. В этот список входят методы object, а также элементы, добавленные через метаклассы. dir() не различает, где именно был объявлен метод, поэтому для анализа структуры класса его используют только совместно с фильтрацией.
Как получить только унаследованные методы без методов самого класса?
Нужно пройтись по цепочке наследования через __mro__, начиная со второго элемента, и собрать методы из __dict__ каждого базового класса. Затем исключить имена, присутствующие в __dict__ дочернего класса. Такой подход корректно работает и при множественном наследовании.
Почему property попадает в список методов при использовании callable()?
property реализует протокол дескриптора и после доступа через экземпляр возвращает результат вызова функции. callable() проверяет только возможность вызова объекта, поэтому property может пройти эту проверку. Для исключения свойств требуется отдельная проверка через isinstance(obj, property) на уровне класса.
Как отличить метод экземпляра от classmethod и staticmethod?
В __dict__ класса метод экземпляра представлен объектом function. classmethod и staticmethod являются обёртками и требуют проверки через isinstance(obj, classmethod) и isinstance(obj, staticmethod). Использование inspect.isfunction() позволяет получить только методы экземпляра без дополнительных условий.
Можно ли определить, из какого базового класса пришёл конкретный метод?
Да. Нужно пройтись по __mro__ в порядке разрешения методов и проверить, в __dict__ какого класса впервые встречается имя метода. Первый найденный класс и будет источником реализации, используемой данным классом.
