1

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

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()

注意我不希望proxy.get_a().do_something()返回任何明智的东西,它只是应该做的事情。

4

2 回答 2

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
于 2012-11-24T22:53:42.157 回答
2

最pythonic的方式可能是列表理解

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

如果要在多个地方使用缓存,则需要根据键缓存结果以区分它们,并且为了方便起见,编写一个装饰器,您可以简单地包装要缓存其结果的函数。

在Python Algorithms: Mastering Basic Algorithms in the Python Language中找到了一个很好的例子(参见这个问题)。针对您的情况进行了修改,不使用函数参数,而是使用函数名作为缓存键,它看起来像这样:

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]
于 2012-11-24T21:54:35.473 回答