如何在Python中创建对象集合代理?

时间:2012-11-24 21:26:00

标签: python object collections proxy

我正在尝试创建一个对象集合代理,可以执行以下操作:

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()返回任何合理的东西,它只应该做的事情。

2 个答案:

答案 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]