1

我正在编写一些我想作为函数调用的实用程序。它们是用一个不会改变的上下文和一些数据来调用的。处理上下文需要花费大量时间,但是一旦完成,用它来暴露数据是相当轻量级的。

这显然会很好地映射到以下模式

class MyFunc():
    def __init__(self, context):
        self.foo_d_context=foo(context)
    def __call__(self, data):
        return bar(self.foo_d_context, data)

if __name__ == '__main__':
    my_callable=MyFunc(my_context)

    results1=my_callable(my_data1)
    results2=my_callable(my_data2)

但是,我的用户反对 my_callable 对象的初始创建。他们更能接受的是一个可以像...一样使用的功能

结果=我的函数(我的上下文,我的数据)

...并让函数 my_func 查看先前调用的持久数据是否存在,并且与上次调用相同。

这样做的问题是第一次调用该函数,它可以将持久数据存储在哪里?似乎 Python 标准库中已经有几个实用程序说它们是这样工作的,并且文档讨论了设置对象的辅助函数。但我还没有弄清楚它是如何工作的。

我可以想到一种方法,但感觉是错误的和不合常规的。看来我可以将对象直接放入 globals() 命名空间,并在任何函数中这样做。所以我可以做

def my_func(context,data):
    glob=globals()
    try:
        if glob['__my_persistent_reference_context_$$$'] == context:
            return bar(glob['__my_foo_d_context_$$$'],data)
    except KeyError:
        pass
    glob['__my_foo_d_context_$$$']=foo(context)
    glob['__my_persistent_reference_context_$$$'] = context
    return bar(glob['__my_foo_d_context_$$$'],data)

写完上面的内容,我突然想到这个函数可以创建一个 MyFunc 类的对象,这听起来更接近我正在寻找的概念,但它仍然必须给它起个名字,把它放在某个地方,这样就不会'不解决基本的'我可以使用全局命名空间吗?' 问题。

这个可以吗?

它会一直有效吗?(我使用的是 2.6.6,它最终会在 3 中工作吗?)

有更好的方法吗?

有没有更好的命名空间来污染?

我是否应该坚持认为上课的方式只是正确的方式?

4

2 回答 2

2

从您所说的来看,我认为您想要做的是缓存一个值。这可以通过使用不会侵入其他命名空间的函数属性来轻松完成。

def my_func(context, data):
    try:
        reference, saved = my_func.cache
    except AttributeError:
        reference, saved = None, None
    computed = saved if reference == context else foo(context)
    my_func.cache = context, computed
    return bar(computed, data)
于 2013-01-09T16:37:13.037 回答
0

当然,您可以放入任何内容,globals()并且如果您在密钥中使用使其无效的字符作为标识符,则无法以“正常”方式访问它。但是,让我们一步一步来。如果你要使用字典,为什么不使用你自己的呢? 你甚至不需要在任何使用它的函数中声明它是全局的。

_my_global_state = {}

def foo(x):
    _my_global_state.setdefault("counter", 0)
    _my_global_state["counter"] += x

等等。

但是属性语法更好,所以让我们使用一个对象实例:

_my_global_state = object()

def foo(x):
    if hasattr(_my_global_state, "counter"):
        _my_global_state.counter += x
    else:
        _my_global_state.counter = x

当然,在实现了这一飞跃之后,现在您不妨将数据和函数放在一起成为一个单一的……东西。这是真正的解决方案。使用类来保存您的数据和对其进行操作的函数。

于 2013-01-09T16:31:25.807 回答