getattr(): доступ к атрибутам по строковому имени
Функция getattr() в Python возвращает значение атрибута объекта, имя которого передано строкой. Она нужна, когда имя поля или метода становится известно только во время работы программы. Ниже разобраны параметры функции, поведение при отсутствии атрибута, вызов методов по имени и типичные ошибки.

Содержание статьи
Синтаксис и параметры
getattr - встроенная функция, импортировать ее не нужно. Сигнатура выглядит так:
getattr(object, name)
getattr(object, name, default)object- любой объект: экземпляр класса, сам класс, модуль, функция.name- имя атрибута строкой. Передача числа или другого типа вызовет TypeError.default- необязательное значение, которое вернется, если атрибута нет.
Вызов getattr(obj, "name") полностью эквивалентен записи obj.name. Срабатывают те же механизмы: поиск в экземпляре, затем в классе и родителях, вызов свойств и дескрипторов.
class Student:
school = "Лицей 1"
def __init__(self, name, marks):
self.name = name
self.marks = marks
st = Student("Анна", 88)
print(getattr(st, "name")) # Анна
print(getattr(st, "marks")) # 88
print(getattr(st, "school")) # Лицей 1, атрибут классаЕсли вы еще не знакомы с атрибутами экземпляра и класса, прочитайте статью про классы и объекты.
Значение по умолчанию и AttributeError
Когда атрибута нет, поведение зависит от третьего аргумента. Без него выбрасывается исключение, с ним возвращается заданное значение.
class Person:
age = 23
p = Person()
print(getattr(p, "city", "не указан")) # не указан
try:
getattr(p, "city")
except AttributeError as e:
print(e) # 'Person' object has no attribute 'city'Значение по умолчанию заменяет связку из проверки hasattr() и обращения к атрибуту. Код email = getattr(user, "email", None) короче и выполняет поиск один раз.
Учтите, что default перехватывает только AttributeError. Если внутри свойства возникнет другое исключение, например ZeroDivisionError, оно пройдет наружу. А вот AttributeError, случайно возникший внутри property из-за опечатки, будет молча заменен значением по умолчанию, что затрудняет поиск ошибки.
Вызов метода по имени
Методы тоже являются атрибутами, поэтому getattr возвращает связанный метод, который можно сразу вызвать. Так строятся простые диспетчеры команд без длинных цепочек if и elif.
class Calculator:
def add(self, a, b):
return a + b
def mul(self, a, b):
return a * b
calc = Calculator()
for op in ("add", "mul", "pow"):
method = getattr(calc, op, None)
if callable(method):
print(op, method(3, 4))
else:
print(op, "не поддерживается")
# add 7
# mul 12
# pow не поддерживаетсяЕсли имя метода приходит от пользователя, ограничьте допустимые варианты. Иначе через getattr можно добраться до служебных атрибутов вроде __class__ или __dict__. Надежный прием - проверять имя по белому списку или требовать общий префикс, например cmd_.
Получение функций из модуля
Модуль в Python - тоже объект, поэтому getattr работает и с ним. Это удобно, когда имя функции хранится в конфигурации.
import math
func = getattr(math, "sqrt")
print(func(16)) # 4.0getattr и родственные функции
Для работы с атрибутами по имени в Python есть целое семейство встроенных функций. Они часто используются вместе.
| Функция | Что делает | Аналог через точку |
|---|---|---|
getattr(obj, "x") | Читает атрибут | obj.x |
setattr(obj, "x", 5) | Создает или меняет атрибут | obj.x = 5 |
hasattr(obj, "x") | Проверяет наличие, возвращает bool | нет |
delattr(obj, "x") | Удаляет атрибут | del obj.x |
dir(obj) | Список доступных имен | нет |
Подробнее об удалении атрибутов и просмотре их списка написано в статьях про delattr и dir. Пример совместного использования - копирование полей из словаря в объект:
class Config:
pass
cfg = Config()
for key, value in {"debug": True, "port": 8080}.items():
setattr(cfg, key, value)
print(getattr(cfg, "port")) # 8080Связь с методом __getattr__
Функцию getattr не стоит путать с магическим методом __getattr__. Метод определяется в классе и вызывается интерпретатором только тогда, когда обычный поиск атрибута ничего не нашел. Так делают прокси-объекты и значения по умолчанию для любых полей.
class Settings:
def __init__(self, data):
self._data = data
def __getattr__(self, name):
try:
return self._data[name]
except KeyError:
raise AttributeError(name) from None
s = Settings({"theme": "dark"})
print(s.theme) # dark
print(getattr(s, "lang", "ru")) # ruВнутри __getattr__ важно выбрасывать именно AttributeError: тогда hasattr() и getattr с default работают корректно. Подробнее о специальных методах в статье про магические методы.
Подводные камни
Несколько особенностей, о которых полезно знать заранее:
- Аргумент default вычисляется всегда, даже если атрибут найден. Запись
getattr(obj, "x", heavy_call())выполнит тяжелую функцию в любом случае. - getattr не понимает точки в имени:
getattr(user, "address.city")ищет атрибут с точкой в названии. Для вложенного пути используйтеoperator.attrgetter("address.city")(user). - Если атрибут существует и равен None, getattr вернет None, а не default. Отличить отсутствие от None можно через уникальный объект-маркер
MISSING = object(). - Когда имя известно заранее, обычная запись через точку понятнее и чуть быстрее.
Формальное описание функции приведено в документации Python.
Частые вопросы
Короткие ответы на популярные вопросы о getattr.
Чем getattr отличается от obj.__dict__[name]?
Словарь __dict__ содержит только атрибуты самого экземпляра. getattr ищет еще в классе и родителях, вызывает свойства и __getattr__, а также работает с объектами, у которых нет __dict__.
Можно ли через getattr получить приватный атрибут?
Атрибут с одним подчеркиванием доступен как обычно. Имена с двумя подчеркиваниями искажаются интерпретатором, поэтому __secret класса User доступен как getattr(obj, "_User__secret").
Что лучше: hasattr или getattr с default?
Если значение нужно сразу после проверки, используйте getattr с default: один поиск вместо двух. hasattr уместен, когда нужен только ответ да или нет.
Работает ли getattr со словарями?
Ключи словаря не являются атрибутами, поэтому getattr(d, "key") выбросит AttributeError. Для словарей используйте d.get("key", default).