django中LazyObject实现延迟加载

58 阅读1分钟

django中使用LazyObject实现延迟实例化某个对象,直到真正要用到它的时候才进行初始化。这种设计可以提升性能、减少资源消耗,并避免循环依赖。 django中的实现

# 初始化django配置
django.setup()

def setup(set_prefix=True):
    """
    Configure the settings (this happens as a side effect of accessing the
    first setting), configure logging and populate the app registry.
    Set the thread-local urlresolvers script prefix if `set_prefix` is True.
    """
    from django.apps import apps
    from django.conf import settings
    from django.urls import set_script_prefix
    from django.utils.log import configure_logging

    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
    if set_prefix:
        set_script_prefix(
            "/" if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME
        )
    # 配置延迟加载
    apps.populate(settings.INSTALLED_APPS)

写一个demo来解释

empty = object()

class LazyObject:
    """
    A class that allows for lazy initialization of an object.
    The object is not created until it is accessed for the first time.
    """
    _wrapped = None
    def __init__(self):
        self._wrapped = empty
    
    def __getattr__(self, name):
        if self._wrapped is empty:
            self._setup()
        return getattr(self._wrapped, name)

    def __setattr__(self, name, value):
        print(f"Setting attribute {name} to {value}")
        if name == '_wrapped':
            self.__dict__['_wrapped'] = value
        else:
            if self._wrapped is empty:
                self._setup()
            setattr(self._wrapped, name, value)
    
    def _setup(self):
        """
        This method should be overridden to initialize the wrapped object.
        It is called the first time an attribute is accessed.
        """
        raise NotImplementedError("Subclasses must implement _setup method")


class HeavyClass:
    def __init__(self):
        print("HeavyClass initialized")
        self.value = 42
    
    def get_value(self):
        return self.value


class LazyHeavyObject(LazyObject):
    def _setup(self):
        print("Setting up HeavyClass instance")
        self._wrapped = HeavyClass()

# Example usage
obj = LazyHeavyObject()
print("LazyHeavyObject created, but HeavyClass not initialized yet.")

# This will trigger the initialization of HeavyClass and print the value.
print("Value from HeavyClass:", obj.get_value())

运行结果

Setting attribute _wrapped to <object object at 0x000001E022534500>
LazyHeavyObject created, but HeavyClass not initialized yet.
Setting up HeavyClass instance
HeavyClass initialized
Setting attribute _wrapped to <__main__.HeavyClass object at 0x000001E022CA7CD0>
Value from HeavyClass: 42