@Mikkkch

Почему многие в настройках своих библиотек помещают импорт объекта в метод __getattr__?

Думаю многие заглядывали в исходный код используемых библиотек, которые идут в дополнение Django и Django REST.
Вот, например, код настроек фреймворка Django REST, идущего в дополнение к Django.
class APISettings:
    def __init__(self, user_settings=None, defaults=None, import_strings=None):
        if user_settings:
            self._user_settings = self.__check_user_settings(user_settings)
        self.defaults = defaults or DEFAULTS
        self.import_strings = import_strings or IMPORT_STRINGS
        self._cached_attrs = set()

    def __getattr__(self, attr):
        if attr not in self.defaults:
            raise AttributeError("Invalid API setting: '%s'" % attr)

        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

        # Coerce import strings into classes
        if attr in self.import_strings:
            val = perform_import(val, attr)

        # Cache the result
        self._cached_attrs.add(attr)
        setattr(self, attr, val)
        return val

Здесь, обращаясь к какому-либо атрибуту вызывается метод, импортирующий объект, располагающийся по строковому пути. Зачем каждый раз, когда будет осуществляться обращение к импортируемому атрибуту его импортировать? Нельзя сразу в методе init установить импортированную строку, чтобы потом каждый раз не приходилось производить операцию?
Может я неправильно понимаю, как работает этот метод? Вот если что код еще одного человека, использующего такой подход:
class NestedSettings:
    def __init__(
            self, user_settings, defaults, import_strings,
            root_setting_name):
        if user_settings:
            self._user_settings = user_settings
        self.defaults = defaults
        self.import_strings = import_strings
        self.root_setting_name = root_setting_name

    def __getattr__(self, attr):
        if attr not in self.defaults.keys():
            raise AttributeError(
                "Invalid {self.root_setting_name} setting: '{attr}'".format(
                    self=self, attr=attr))

        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

        # Coerce import strings into classes
        if attr in self.import_strings:
            val = perform_import(val, attr)

        # Cache the result
        setattr(self, attr, val)
        return val

Код, как можете заметить, не сильно отличается.
P.S перечислены не все методы классов, если нужен фулл код, то вот ссылки:
https://github.com/apragacz/django-rest-registrati...
https://github.com/encode/django-rest-framework/bl...
  • Вопрос задан
  • 70 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы