为什么使用object.__setattr__

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__的情况,一般也是为了避免无限递归。

July 23, 2019 · 1 min · Egbert Ke

理解werkzeug中的Local对象

ThreadLocal是线程级别的local,如果在greenlet或者协程这种微线程环境下,或者在多个请求共用一个线程的情况下,线程级别是不够的。ThreadLocal是thread-safe和thread-specific的, 而有些情况需要greenlet-safe和greenlet-specific或者request-safe和request-specific。 werkzeug 0.1版中Local的实现是这样的: try: from py.magic import greenlet get_current_greenlet = greenlet.getcurrent del greenlet except (RuntimeError, ImportError): get_current_greenlet = lambda: None try: from thread import get_ident as get_current_thread from threading import Lock except ImportError: from dummy_thread import get_ident as get_current_thread from dummy_threading import Lock from werkzeug.utils import ClosingIterator def get_ident(): """ Return a unique number for the current greenlet in the current thread. """ return hash((get_current_thread(), get_current_greenlet())) class Local(object): def __init__(self): self....

July 18, 2019 · 2 min · Egbert Ke