我正在尝试创建一个对象集合代理,可以执行以下操作:
class A:
def do_something():
# ...
class B:
def get_a():
return A()
class Proxy:
?
collection = [B(), B()]
proxy = Proxy(collection)
proxy.get_a().do_something()
# ^ for each B in collection get_a() and do_something()
实现这一目标的最佳架构/策略是什么?
关键问题,我想是,如何缓存get_a()的结果,以便我可以代理do_something()
N.B。我不希望proxy.get_a().do_something()
返回任何合理的东西,它只应该做的事情。
答案 0 :(得分:3)
足够简单......您可能希望对其进行调整以进行更多检查
class A(object):
def do_something(self):
print id(self), "called"
class B(object):
def get_a(self):
return A()
class Proxy(object):
def __init__(self, objs):
self._objs = objs
def __getattr__(self, name):
def func(*args, **kwargs):
return Proxy([getattr(o, name)(*args, **kwargs) for o in self._objs])
return func
collection = [B(), B()]
proxy = Proxy(collection)
proxy.get_a().do_something()
结果:
4455571152 called
4455571216 called
答案 1 :(得分:2)
最常用的方式可能是list comprehension:
results = [b.get_a().do_something() for b in collection]
如果要缓存B.get_a()
的来电,可以使用memoization。自己进行记忆的简单方法可能如下所示:
cache = None
# ...
class B:
def get_a(self):
global cache
if cache is None:
cache = A()
return cache
如果你想在多个地方使用缓存,你需要根据键缓存结果以区分它们,为了方便起见,写一个decorator你可以简单地用你的结果包装函数想要缓存。
Python算法:掌握Python语言中的基本算法中可以找到一个很好的例子(参见this question)。根据你的情况修改,不使用函数参数而是使用函数名作为缓存键,它看起来像这样:
from functools import wraps
def memoize(func):
cache = {}
key = func.__name__
@ wraps(func)
def wrap(*args):
if key not in cache:
cache[key] = func(*args)
return cache[key]
return wrap
class A:
def do_something(self):
return 1
class B:
@memoize
def get_a(self):
print "B.get_a() was called"
return A()
collection = [B(), B()]
results = [b.get_a().do_something() for b in collection]
print results
输出:
B.get_a() was called
[1, 1]