我有文件services.py,其中包含某些类MyCache。 MyCache的所有实例都应共享一个“缓存”字段,因此我将其设置为静态。为了初始化缓存,有一个加载它的静态方法。这个方法在app的最开始只调用一次。
问题是当我从其他.py文件导入services.py并创建MyCache实例时 - 它打印出该缓存是空的!
如何修复它并让所有类的实例共享“缓存”字段而忽略它们的创建位置?
我无法理解为什么会这样。请帮助:)
services.py:
class MyCache:
cache = {}
@staticmethod
def initialize():
MyCache.cache = load_from_file()
print(len(MyCache.cache)) # prints 3
def __init__(self):
print(len(MyCache.cache)) # supposed to print 3, because initialize has been called earlier, but prints 0 when called from other_file.py
main.py:
import services
if __name__ == '__main__':
services.MyCache.initialize()
other_file.py:
import services
services.MyCache().foo() # creates instance, prints 0 in MyCache.__init__
答案 0 :(得分:1)
#mycache.py
def load_from_file():
pass
...
cache = load_from_file()
#anotherlib.py
from mycache import cache
...
#main.py
from anotherlib import ... #(Now the cache is initialized)
from mycache import cache #(Python looksup the mycache module and doesn't initialize it again)
这里我们只使用python模块作为单例。要了解有关python如何缓存模块以便仅初始化一次的更多信息,请阅读:https://docs.python.org/2/library/sys.html#sys.modules
答案 1 :(得分:1)
一个问题是,在执行期间,在执行初始化的if __name__ == '__main__:
部分之前,您在导入期间使用了类。
您可以使用classmethod
在首次使用时动态初始化类级别缓存。添加一个锁,它也是线程安全的。您不再需要在__main__
中专门初始化,这很容易忘记,您可以随时由其他进口商使用它。
import threading
class MyCache:
cache = None
_lock = threading.Lock()
@classmethod
def initialize(cls):
with cls._lock:
if cls.cache is None:
cls.cache = load_from_file()
def __init__(self):
self.initialize()
print(len(MyCache.cache))
答案 2 :(得分:0)
class MyCache:
cache = {}
__initialized = False
@staticmethod
def initialize():
if not MyCache.__initialized:
MyCache.cache = load_from_file()
MyCache.__initialized = True
def __init__(self):
print(len(MyCache.cache))
答案 3 :(得分:0)
这可能有用 - 如果使用元类不存在,则添加class属性:
foo.py:
def load_stuff():
return {'foo':1, 'bar':2}
class F(type):
def __new__(meta, name, bases, namespace):
if 'cache' not in namespace:
print('adding cache')
namespace['cache'] = load_stuff()
return super().__new__(meta, name, bases, namespace)
class MyCache(metaclass = F):
def __init__(self):
print(len(MyCache.cache))
test.py:
print(__name__)
import foo
print(foo.MyCache.cache)
print('********************')
tmp.py:
print('tmp.py')
import foo
print('*******************')
import test
>>> import tmp
tmp.py
adding cache
*******************
test
{'foo': 1, 'bar': 2}
********************
>>> tmp.foo.MyCache.cache
{'foo': 1, 'bar': 2}
>>> tmp.test.foo.MyCache.cache
{'foo': 1, 'bar': 2}
>>> tmp.test.foo.MyCache.cache['x'] = 'x'
>>> tmp.test.foo.MyCache.cache
{'foo': 1, 'bar': 2, 'x': 'x'}
>>> tmp.foo.MyCache.cache
{'foo': 1, 'bar': 2, 'x': 'x'}
>>>
>>> tmp.foo.MyCache.cache is tmp.test.foo.MyCache.cache
True
>>>
>>> import test
test
adding cache
{'foo': 1, 'bar': 2}
********************
>>> test.foo.MyCache.cache
{'foo': 1, 'bar': 2}
>>>
>>> import tmp
tmp.py
*******************
>>>
>>> tmp.foo.MyCache.cache
{'foo': 1, 'bar': 2}
>>>
>>> tmp.foo.MyCache.cache['x'] = 'x'
>>> tmp.foo.MyCache.cache
{'foo': 1, 'bar': 2, 'x': 'x'}
>>> test.foo.MyCache.cache
{'foo': 1, 'bar': 2, 'x': 'x'}
>>>
>>> z = tmp.foo.MyCache()
3
>>> z.cache
{'foo': 1, 'bar': 2, 'x': 'x'}
>>>
>>> z.cache['y'] = 'y'
>>> z.cache
{'foo': 1, 'bar': 2, 'x': 'x', 'y': 'y'}
>>> test.foo.MyCache.cache
{'foo': 1, 'bar': 2, 'x': 'x', 'y': 'y'}
>>> tmp.foo.MyCache.cache
{'foo': 1, 'bar': 2, 'x': 'x', 'y': 'y'}
>>>
>>> tmp.foo.MyCache.cache is test.foo.MyCache.cache
True
我开始思考并意识到class属性也可以是从dict继承的 singleton 。
temp.py和test.py - 与上面相同
foo.py:
def load_stuff():
return [('a', 1), ('b', 2)]
class Borg:
_shared_state = {}
def __new__(cls, *a, **k):
obj = super().__new__(cls, *a, **k)
obj.__dict__ = cls._shared_state
return obj
class Cache(dict, Borg):
pass
class OneCache(metaclass = F):
cache = Cache(load_stuff())
def __init__(self):
print(len(OneCache.cache))
然后:
>>> import tmp
>>> tmp.foo.OneCache.cache
{'a': 1, 'b': 2}
>>> tmp.test.foo.OneCache.cache
{'a': 1, 'b': 2}
>>> z = tmp.foo.OneCache()
2
>>> z.cache['r'] = 't'
>>> z.cache
{'a': 1, 'b': 2, 'r': 't'}
>>> tmp.foo.OneCache.cache
{'a': 1, 'b': 2, 'r': 't'}
>>> tmp.test.foo.OneCache.cache
{'a': 1, 'b': 2, 'r': 't'}
>>>
>>> tmp.foo.OneCache.cache is tmp.test.foo.OneCache.cache is z.cache
True
>>>