我正在编写一些我想要作为函数调用的实用程序。它们被调用一个不会改变的上下文和一些数据。使用上下文需要花费大量的时间来完成,但是一旦完成,使用它来清理数据就相当轻巧了。
这显然可以很好地映射到以下模式
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中工作吗?)
有更好的方法吗?
是否有更好的命名空间来污染?
我是否应该坚持认为上课的方式是正确的?
答案 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
当然,实现这一飞跃,现在你不妨将数据和功能整合到一个单独的东西中。这是真正的解决方案。使用类来保存数据及其上运行的函数。