werkzeug 0.6.1中Local的初始化是这样的:
class Local(object):
__slots__ = ('__storage__', '__lock__')
def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__lock__', allocate_lock())
我当时很奇怪为什么要用object.__setattr__
, 而不是直接用self.__storage__
, 当我直接用self.__storage__ = {}
实现的时候才发现问题:
self.__storage__
会调用__setattr__
,而__setattr__
中会调用self.__lock__.acquire()
,因为此时self.__lock__
还没有定义, 所以会调用self.__getattr__
,而self.__getattr__
中也会调用self.__lock__.acquire()
, 此后就会一直调用self.__getattr__
,最终导致StackOverflow。
而显示调用object.__setattr__
就不会触发Local内部的__setattr__
,从而避免上述情况。而且两者的效果是一样的,object.__setattr__
的第一个参数是self
,也就是这个实例,所以并不用担心是不是在父类定义了一个公共属性。
类似的还有使用object.__getattribute__
的情况,一般也是为了避免无限递归。