在编写Python代码时,我经常发现自己想要获得类似于Lisp的defvar的行为。基本上,如果某个变量不存在,我想创建它并为其分配一个特定的值。否则,我不想做任何事情,特别是,我不想覆盖变量的当前值。
我环顾四周,发现了这个建议:
try:
some_variable
except NameError:
some_variable = some_expensive_computation()
我一直在使用它并且工作正常。但是,对我而言,这样的代码看起来并非正常。代码是四行,而不是Lisp中需要的代码,它需要异常处理来处理那些不是“特殊”的东西。
背景是我正在进行交互式开发。我经常执行我的Python代码文件,因为我改进了它,而且每次我都不想运行some_expensive_computation()。我可以安排每次启动一个新的Python解释器时手动运行some_expensive_computation(),但我宁愿做一些自动化的事情,特别是这样我的代码可以非交互式运行。一个季节Python程序员将如何实现这一目标?
我正在使用WinXP和SP3,Python 2.7.5通过Anaconda 1.6.2(32位),并在Spyder中运行。
答案 0 :(得分:2)
依赖于具有意义的变量的存在或不存在通常是一个坏主意。而是使用sentinel值来指示变量未设置为适当的值。 None
是此类哨兵的常见选择,但如果这可能是您昂贵计算的可能输出,则可能不合适。
所以,而不是你当前的代码,做这样的事情:
# early on in the program
some_variable = None
# later:
if some_variable is None:
some_variable = some_expensive_computation()
# use some_variable here
或者,None
可能是重要值的版本:
_sentinel = object()
some_variable = _sentinel # this means it doesn't have a meaningful value
# later
if some_variable is _sentinel:
some_variable = some_expensive_computation()
答案 1 :(得分:2)
很难说出您更关心哪个,特定语言功能或持续会话。既然你说:
背景是我正在进行交互式开发。我经常执行我的Python代码文件,因为我改进了它,而且每次我都不想运行some_expensive_computation()。
您可能会发现IPython提供了一个令您满意的持久互动环境。
答案 2 :(得分:1)
不要在Python中编写Lisp,只要想想你正在尝试做什么。你想避免两次调用昂贵的函数并让它运行两次。你可以编写你的函数:
def f(x):
if x in cache:
return cache[x]
result = ...
cache[x] = result
return result
或者使用Python的装饰器,只需使用另一个为您处理缓存的函数来装饰该函数。 Python 3.3附带functools.lru_cache
,它就是这样:
import functools
@functools.lru_cache()
def f(x):
return ...
PyPi for 2.7中有相当多的memoization库。
答案 3 :(得分:1)
对于您提供的用例,使用try ... except
保护似乎是一种很好的方法:您的代码依赖于先前执行脚本的剩余变量。
但我同意这不是一个很好的概念实现"这里是一个默认值,除非变量已经设置,否则使用它#34;。 Python并不直接支持变量,但它确实有一个字典键的默认设置器:
myvalues = dict()
myvalues.setdefault("some_variable", 42)
print some_variable # prints 42
setdefault
的第一个参数必须是字符串,其中包含要定义的变量的名称。
如果您有一个复杂的设置系统和默认设置(如emacs),您可能会将系统设置保存在自己的字典中,因此这就是您所需要的。在您的情况下,您还可以在全局变量(仅)上直接使用setdefault
,借助内置函数globals()
返回可修改的字典:
globals().setdefault("some_variable", 42)
但我建议为持久变量使用字典(可以使用try... except
方法有条件地创建它)。它保持东西清洁,看起来更像...... pythonic。
答案 4 :(得分:0)
让我试着总结一下我在这里学到的东西: