Django 源码分析 LazySetting 对象

一、Django 中通过 LazySetting 对象来获取项目的配置,LazySetting 对象有什么特性?为什么使用这个对象?

LazySetting 顾名思义,就是延迟获取配置内容。比如,我们定义了一个对象A,并对其添加了一些属性,对A初始化时,我们将 A 的属性的值设置为空,当我们要访问 A 其中的一个属性时,此时属性的值为空,我们才加载属性的值,并将空值设置为对应的值,返回属性值,下次获取属性值时,属性值不为空,直接返回属性值。

为什么要使用 LazySetting? 

Django项目在初始化的时候, 通过 LazySetting,我们就可以在 django 获取某个配置的值之前,将配置的值先自定义为某个值,django 再去获取该配置的值的时候,配置已经有了值,直接返回该配置的值。

二、Django是如何实现 LazySetting 对象的?

1. 在说LazySetting对象之前,我们先看一下python的类属性的查找方式:

在查找一个实例化的类属性的时候:

  1. 首先查找这个类的实例属性是否存在,存在直接返回
  2. 如果类的实例属性中不存在,则在类的类属性中查找,类属性中存在,则返回
  3. 如果类属性中也不存在,若定义了__getattr__方法,则根据__getattr__方法获取属性

在python中类属性和实例属性会记录在类的一个内置变量__dict__中,类属性和实例属性有各自维护的__dict__

class A:
    a = '类属性'

    def __init__(self):
        self.a = '实例属性'


print(A.__dict__)
print(A().__dict__)

输出的结果为:

{
    "__module__": "__main__",
    "a": "类属性",
    "__init__": < function A.__init__ at 0x04BBAB28 >,
    "__dict__": < attribute "__dict__" of "A" objects >,
    "__weakref__": < attribute "__weakref__" of "A" objects >,
    "__doc__": None
}

{
    "a": "实例属性"
}

注意的是,类属性里面不只有a属性,还有一些其他类有关的属性

我们可以看到,类属性里面a的值和实例属性里面a的值不一样。类属性和实例属性是分别维护的。

2. 下面我们写几个实例化的类查找属性的例子

第一个例子:

class A:
    a = 'Aa'
    b = 'Bb'

class A:
    a = 'Aa'
    b = 'Bb'

    def __init__(self):
        self.a = 'aa'


obj = A()
print(obj.a)
print(obj.b)
def __init__(self):
        self.a = 'aa'

obj = A()
print(obj.a)
print(obj.b)

输出的结果是(先在实例属性中查找,找不到,再到类属性中查找)

aa
Bb

如果我们print(obj.c)则会报错,因为在类属性中和实例属性中都找不到c

第二个例子:

class A:
    a = 'Aa'
    b = 'Bb'

    def __init__(self):
        self.a = 'aa'

    def __getattr__(self, item):
        return 'cc'

obj = A()
print(obj.a)
print(obj.b)
print(obj.c)

输出的结果和上面类似,只是print(obj.c)不报错了,因为我们定义了__getattr__方法,实例属性中和类属性中都找不到时,就会使用这个方法获取属性

aa
Bb
cc

3. Django的 LazySetting 类的实现

LazySetting类的实现就是通过定义__getattr__方法实现的,LazySetting类的__getattr__源码如下

def __getattr__(self, name):
    """Return the value of a setting and cache it in self.__dict__."""

    if self._wrapped is empty:
        self._setup(name)

    val = getattr(self._wrapped, name)
    self.__dict__[name] = val

    return val

我们在LazySetting对象中查找一个属性的时候,先在实例属性(self.__dict__)中查找,没有找到话,通过__getattr__方式获取,获取到后,将属性值保存到实例属性中,这样就实现了属性在使用的时候

再获取,然后保存。我们还可以再获取属性之前,先将属性的值自定义,这样就可以不用使用__getattr__的方式来获取默认的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值