【问题标题】:How to create an object collection proxy in Python?如何在 Python 中创建对象集合代理?
【发布时间】:2012-11-12 19:17:25
【问题描述】:

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

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

【问题讨论】:

    标签: python object collections proxy


    【解决方案1】:

    足够简单...您可能需要对其进行调整以进行更多检查

    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
    

    【讨论】:

    • 这并没有处理对B.get_a() 的缓存调用(我也首先忽略了这个要求)。但是您的基于类的代理方法和我的回答中的记忆技术应该为@Alex提供他需要的一切:)
    • 其实我想他并不想缓存它。他的意思是如何在调用 do_something 之前存储对 get_A 的调用结果。
    • Lukas,Garet,谢谢,这就是我所追求的。加雷特,你是对的,我只是想通过管道传递它,这样我就可以在我的代码中很好地“链接”下一个调用。
    【解决方案2】:

    最pythonic的方式可能是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]
    

    【讨论】:

    • 谢谢,卢卡斯。可能从我正在寻找一种基于类的方法的问题中不清楚,因为我需要提供一个像 myclass.get_a().do_something() 这样的接口,它会迭代它自己的集合,但是你的答案为我指明了某个方向,所以我会继续挖掘。
    猜你喜欢
    • 1970-01-01
    • 2020-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多