M
M
Mikkkch2021-02-01 11:49:56
Django
Mikkkch, 2021-02-01 11:49:56

Why do many people in the settings of their libraries put the import of the object in the __getattr__ method?

I think many looked into the source code of the libraries used, which go in addition to Django and Django REST.
For example, here is the Django REST framework configuration code that comes in addition to 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

Here, referring to any attribute, a method is called that imports an object located at a string path. What for each time when the appeal to imported attribute will be carried out to import it? Is it not possible to immediately set the imported string in the init method, so that later each time you do not have to perform the operation?
Am I misunderstanding how this method works? Here's the code of another person using this approach:
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

The code, as you can see, is not much different.
PS Not all class methods are listed, if you need a full code, then here are the links:
https://github.com/apragacz/django-rest-registrati...
https://github.com/encode/django-rest-framework/ bl...

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question