我可以使用(误用)globals()命名空间来持久存储吗?

时间:2013-01-09 16:19:16

标签: python namespaces

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

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

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对象。他们更容易接受的是一个可以像...一样使用的功能。

results = my_func(my_context,my_data)

...并让函数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中工作吗?)

有更好的方法吗?

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

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

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分: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

当然,实现这一飞跃,现在你不妨将数据和功能整合到一个单独的东西中。这是真正的解决方案。使用类来保存数据及其上运行的函数。