Getattr: примеры (PYTHON)

Динамический доступ к атрибутам: функция getattr в Python
Раздел: Встроенные функции, Доступ к атрибутам
getattr(object: any, name: str, default: any): any

Описание функции getattr

Функция getattr() в Python предназначена для получения значения атрибута объекта по его имени, заданному в виде строки. Это один из инструментов интроспекции и метапрограммирования, позволяющий работать с атрибутами динамически.

Функция используется в ситуациях, когда имя атрибута становится известно только во время выполнения программы. Например, при обработке конфигурационных файлов, реализации плагинов, динамической диспетчеризации методов или сериализации данных.

Аргументы функции

  • object (обязательный): Объект, атрибут которого требуется получить.
  • name (обязательный): Строка, содержащая имя атрибута. Должна быть корректным идентификатором Python, если атрибут не является специальным (например, элементом __dict__).
  • default (необязательный): Значение, которое возвращается, если атрибут с указанным именем не найден. Если этот аргумент не задан, а атрибут отсутствует, возникает исключение AttributeError.

Возвращаемое значение

Функция возвращает значение атрибута объекта. Если атрибут не существует и задан аргумент default, возвращается его значение. Если атрибут не существует и аргумент default не задан, возбуждается исключение AttributeError.

Простые примеры использования

Пример получения существующего атрибута:

class Example:
    value = 10

obj = Example()
attr_value = getattr(obj, 'value')
print(attr_value)
10

Пример с несуществующим атрибутом и значением по умолчанию:

result = getattr(obj, 'unknown', 'default_value')
print(result)
default_value

Пример вызова метода через getattr:

class Greeter:
    def say_hello(self):
        return "Hello!"

g = Greeter()
method = getattr(g, 'say_hello')
print(method())
Hello!

Похожие функции в Python

  • hasattr(object, name): Проверяет наличие атрибута у объекта. Возвращает True или False. Часто используется вместе с getattr для безопасного доступа.
  • setattr(object, name, value): Устанавливает значение атрибута объекта по имени (строке). Является операцией, обратной getattr.
  • delattr(object, name): Удаляет атрибут у объекта по имени.
  • Оператор точки (.): Прямой доступ к атрибуту, когда его имя известно на этапе написания кода. Более эффективен и рекомендуется для статического доступа.

Функция getattr предпочтительнее оператора точки, когда имя атрибута динамическое или хранится в переменной. hasattr используют для проверки перед вызовом getattr без значения по умолчанию.

Аналоги функции в других языках

JavaScript: Доступ через квадратные скобки или оператор ?..

const obj = { value: 42 };
const attrName = 'value';
console.log(obj[attrName]); // 42
console.log(obj?.unknown); // undefined
42
undefined

PHP: Используют синтаксис ${$variable} для свойств или функцию property_exists.

class Example { public $value = 10; }
$obj = new Example();
$attr = 'value';
echo $obj->{$attr}; // 10
10

Java: Рефлексия через класс java.lang.reflect.

import java.lang.reflect.*;

class Example { public int value = 10; }

public class Main {
    public static void main(String[] args) throws Exception {
        Example obj = new Example();
        Field field = Example.class.getField("value");
        System.out.println(field.get(obj)); // 10
    }
}
10

C#: Использование рефлексии или оператора dynamic.

using System;
using System.Reflection;

class Example { public int value = 10; }

class Program {
    static void Main() {
        Example obj = new Example();
        Type type = obj.GetType();
        PropertyInfo prop = type.GetProperty("value");
        Console.WriteLine(prop.GetValue(obj)); // 10
    }
}
10

Golang: Пакет reflect для рефлексии.

package main

import (
    "fmt"
    "reflect"
)

type Example struct {
    Value int
}

func main() {
    obj := Example{Value: 10}
    v := reflect.ValueOf(obj)
    field := v.FieldByName("Value")
    fmt.Println(field.Int()) // 10
}
10

В отличие от Python, во многих языках динамический доступ к атрибутам требует более многословного синтаксиса рефлексии.

Типичные ошибки

Ошибка при отсутствии атрибута без значения по умолчанию:

class Demo:
    pass

obj = Demo()
try:
    val = getattr(obj, 'missing')
except AttributeError as e:
    print(f"Ошибка: {e}")
Ошибка: 'Demo' object has no attribute 'missing'

Передача нестрокового имени атрибута:

try:
    val = getattr(obj, 123)
except TypeError as e:
    print(f"Ошибка: {e}")
Ошибка: getattr(): attribute name must be string

Использование getattr для приватных атрибутов с одним подчеркиванием возможно, но для имен с двумя подчеркиваниями происходит искажение имени.

class Test:
    def __init__(self):
        self.__private = 1

obj = Test()
# Прямой доступ к имени с искажением
val = getattr(obj, '_Test__private')
print(val)  # 1
1

Изменения в последних версиях Python

В Python 3.10 была улучшена обработка ошибок для getattr в сочетании с property. Если свойство (@property) возбуждает исключение AttributeError внутри геттера, это исключение теперь правильно проксируется как AttributeError из getattr, а не преобразуется в RuntimeError.

В Python 3.9 и более ранних версиях поведение функции getattr оставалось стабильным. Существенных изменений в синтаксисе или основных возможностях не происходило.

Расширенные примеры применения

Динамический выбор метода на основе конфигурации:

Пример python
class DataProcessor:
    def process_json(self, data):
        return "JSON processed"
    def process_xml(self, data):
        return "XML processed"

processor = DataProcessor()
config_format = "json"  # Может приходить из настроек
method_name = f"process_{config_format}"
if hasattr(processor, method_name):
    method = getattr(processor, method_name)
    result = method("some_data")
    print(result)
JSON processed

Имитация цепочки вызовов с обработкой отсутствующих атрибутов:

Пример python
class SafeAccessor:
    def __init__(self, obj):
        self._obj = obj
    def __getattr__(self, name):
        # Позволяет безопасно получать атрибуты
        return getattr(self._obj, name, None)

class ComplexObject:
    inner = None

obj = ComplexObject()
safe = SafeAccessor(obj)
# Попытка доступа к вложенному атрибуту
value = safe.inner.unknown
print(value)  # None, а не AttributeError
None

Использование со специальными методами (dunder methods):

Пример python
class CustomList:
    def __init__(self, items):
        self.items = items
    def __len__(self):
        return len(self.items)

lst = CustomList([1, 2, 3])
# Получение специального метода
len_func = getattr(lst, '__len__')
print(len_func())  # 3
# Альтернативно, можно вызвать через объект
print(lst.__len__())
3
3

Применение в фабриках и плагинах:

Пример python
PLUGINS = {'json': 'JsonParser', 'csv': 'CsvParser'}

class JsonParser:
    def parse(self):
        return "Parsing JSON"

class CsvParser:
    def parse(self):
        return "Parsing CSV"

def get_plugin(plugin_name):
    plugin_class = globals().get(PLUGINS.get(plugin_name))
    if plugin_class:
        return plugin_class()
    return None

plugin = get_plugin('json')
if plugin:
    parse_method = getattr(plugin, 'parse', lambda: 'No method')
    print(parse_method())
Parsing JSON

питон getattr function comments

En
Getattr Get object attribute