5

我在 Ruby 中遇到了一个有趣的表达式:

a ||= "new"

这意味着如果没有定义a,“新”值将被分配给a;否则, a 将与原来相同。在进行一些数据库查询时很有用。如果设置了该值,我不想触发另一个数据库查询。

所以我在 Python 中尝试了类似的心态:

a = a if a is not None else "new"

它失败了。我认为这是因为如果未定义 a,您无法在 Python 中执行“a = a”。

所以我能出来的解决方案是检查 locals() 和 globals(),或者使用 try...except 表达式:

myVar = myVar if 'myVar' in locals() and 'myVar' in globals() else "new"

或者

try:
    myVar
except NameError:
    myVar = None

myVar = myVar if myVar else "new"

正如我们所看到的,解决方案并不那么优雅。所以我想问一下,有没有更好的方法呢?

4

6 回答 6

5

使用未定义的变量作为“默认值”有点代码味道。a = a正如您所发现的,它失败了,因为如果 a 不存在,您将无法执行。最好用一些默认值(如无)初始化你的变量,然后检查它。所以你几乎找到了解决方案。唯一的事情是,您应该明确地初始化它,而不是让您的变量未初始化并尝试使用“不存在”作为“缺失”值。所以,而不是这样做:

 # code with no initialization. . .
 a ||= blah

做这个:

a = None
# code
if a is None:
    a = blah
于 2012-07-20T07:15:23.063 回答
3

怎么样?

try:
    a = a
except NameError:
    a = "new"

它不是很短,但确实(至少对我而言)清楚地解释了代码的意图。

于 2012-07-20T07:40:19.523 回答
1

Pythonic 是您在使用它之前应该知道它,尤其是在本地/全局变量中,而不是猜测它在哪里。您可以编写此代码,但它不是 pythonic

a = None
# other codes
a = a or 'new'

没事儿

于 2012-07-20T09:08:27.857 回答
1

如果你真的想要这种行为,你最好在 Python 中使用 a dict,例如:d.get('a', 'new')。这意味着你可以用globals()/搞砸locals()get('a', 'new'),但这通常不是在 Python 中做事的方式——每个名称绑定都应该有一个初始值,即使它是某种标记值(例如None)。

使用 globals() 和使用 setdefault() 的可怕示例

>>> a
Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    a
NameError: name 'a' is not defined
>>> globals().setdefault('a', 'new')
'new'
>>> a
'new'
>>> a = 'old'
>>> globals().setdefault('a', 'new')
'old'
>>> a
'old'
于 2012-07-20T07:22:35.827 回答
1

考虑使用非常 Pythonic 的 memoization。这是一些 Python 2 代码:

# Backport of Python 3's lru_cache
# pip install functools32
from functools32 import lru_cache

@lru_cache()
def expensive_db_query(arg):
    print "Running expensive db query for", arg
    return arg[::-1]

expensive_db_query("spam") # prints "Running expensive db query for spam"
expensive_db_query("spam") # No output
expensive_db_query("eggs") # prints "Running expensive db query for eggs"

如果您想让缓存在经过足够的时间后忘记值并再次查询数据库,请查看Ilialuk 的 lru 缓存

于 2014-03-17T16:28:41.613 回答
0

这是一个受此答案启发的关于如何检查变量是否已定义的变体:

a = a if "a" in vars() or "a" in globals() else "new"

它不是那么短,但至少是一条线。

In [1]: a
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-60b725f10c9c> in <module>()
----> 1 a

NameError: name 'a' is not defined

In [2]: a = a if "a" in vars() or "a" in globals() else "new"

In [3]: a
Out[3]: 'new'

In [4]: a = "A exists!"

In [5]: a = a if "a" in vars() or "a" in globals() else "new"

In [6]: a
Out[6]: 'A exists!'

也就是说,我同意 BrenBarn 的观点,即您应该通过a=None在可能未设置它的块之前声明它来避免未定义变量的问题。

于 2017-11-30T10:01:15.280 回答