1

在编写 Python 代码时,我经常发现自己想要获得类似于 Lisp 的 defvar 的行为。基本上,如果某个变量不存在,我想创建它并为其分配一个特定的值。否则,我不想做任何事情,特别是,我不想覆盖变量的当前值。

我在网上看了一圈,发现了这个建议:

try:
    some_variable
except NameError:
    some_variable = some_expensive_computation()

我一直在使用它,它工作正常。但是,对我来说,这看起来代码在范式上并不正确。代码是四行,而不是在 Lisp 中需要的 1 行,并且它需要异常处理来处理非“异常”的东西。

上下文是我正在进行交互式开发。随着我改进它,我经常执行我的 Python 代码文件,并且我不想每次运行时都运行 some_expensive_computation()。我可以安排每次启动新的 Python 解释器时手动运行 some_expensive_computation(),但我宁愿做一些自动化的事情,特别是这样我的代码可以非交互地运行。一个季节 Python 程序员将如何实现这一目标?

我正在使用带有 SP3 的 WinXP、通过 Anaconda 1.6.2(32 位)的 Python 2.7.5,并在 Spyder 中运行。

4

5 回答 5

2

很难说出您更关心哪个、特定的语言功能或持续会话。既然你说:

上下文是我正在进行交互式开发。随着我改进它,我经常执行我的 Python 代码文件,并且我不想每次运行时都运行 some_expensive_computation()。

您可能会发现IPython提供了一个令您满意的持久的、交互式的环境。

于 2013-10-06T23:10:07.557 回答
2

依赖有意义的变量的存在与否通常是一个坏主意。相反,使用标记值来指示变量未设置为适当的值。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()
于 2013-10-06T23:00:59.627 回答
1

对于您提供的用例,使用 a 进行保护try ... except似乎是一种好方法:您的代码取决于先前执行脚本的剩余变量。

但我同意这不是“这是一个默认值,除非变量已经设置,否则使用它”这个概念的一个很好的实现。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 不知何故。

于 2013-10-06T23:09:12.507 回答
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 中有很多记忆库。

于 2013-10-06T23:00:53.180 回答
0

让我试着总结一下我在这里学到的东西:

  1. 在 Python 中使用异常处理进行流控制很好。我可以做一次来设置一个字典,我可以在其中存储我想要的任何东西。
  2. 有一些库和语言特性是为某种形式的持久性而设计的;这些可以为某些应用程序提供“高速公路”解决方案。搁置模块在这里是一个明显的候选者,但我会足够广泛地解释“某种形式的持久性”,以包括@Blender 的使用记忆的建议。
于 2013-10-08T03:15:38.010 回答