python中是否有类似于ruby';||=

python中是否有类似于ruby';||=,python,ruby,expression,Python,Ruby,Expression,我在Ruby中遇到了一个有趣的表达: a ||= "new" 这意味着,如果未定义a,“新”值将分配给a;否则,a将保持不变。它在执行一些数据库查询时非常有用。如果设置了该值,我不想触发另一个DB查询 因此,我在Python中尝试了类似的思维方式: a = a if a is not None else "new" 它失败了。我认为这是因为如果没有定义a,就无法在Python中执行“a=a” 所以我可以得出的解决方案是检查locals()和globals(),或者使用try…except表达

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

a ||= "new"
这意味着,如果未定义a,“新”值将分配给a;否则,a将保持不变。它在执行一些数据库查询时非常有用。如果设置了该值,我不想触发另一个DB查询

因此,我在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"


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

使用未定义的变量作为“默认值”有点代码味道。正如您所发现的,它失败了,因为如果a不存在,您就不能执行
a=a
。最好用一些默认值(比如无)初始化变量,然后进行检查。所以你基本上找到了解决办法。唯一的问题是,与其让变量保持非斜体,并尝试使用“不存在”作为“缺少”值,不如显式初始化它。因此,与其这样做,不如:

 # code with no initialization. . .
 a ||= blah
这样做:

a = None
# code
if a is None:
    a = blah

如果您真的想要这种行为,最好在Python中使用
dict
,例如:
d.get('a','new')
。这意味着您可以使用
globals()

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

>>a
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
A.
NameError:未定义名称“a”
>>>globals().setdefault('a','new')
“新的”
>>>a
“新的”
>>>a=‘旧’
>>>globals().setdefault('a','new')
“旧的”
>>>a
“旧的”
怎么样

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

它不是很短,但很清楚(至少对我来说)解释了代码的意图。

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

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

没关系

考虑使用备忘录,这是一种很好的解压方式。下面是一些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"

如果希望缓存在足够长的时间后忘记值并再次查询数据库,请签出

以下是一个变体,其灵感来源于如何检查变量是否已定义:

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!'
[1]中的
:a
---------------------------------------------------------------------------
NameError回溯(最近一次呼叫上次)
在()
---->1A
NameError:未定义名称“a”
在[2]中:如果vars()中的“a”或globals()中的“a”,则a=a,否则为“new”
在[3]中:a
Out[3]:“新建”
在[4]中:a=“a存在!”
在[5]中:如果vars()中的“a”或globals()中的“a”,则a=a,否则为“new”
在[6]中:a
Out[6]:“A存在!”

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

注意
variable | |=value
的通常用法是将默认值设置为已定义的变量,用它来定义可能存在也可能不存在的变量是一种糟糕的做法。我认为,尝试除外的解决方案是最具python风格的。当然,它不像单个运算符那样简洁,但它清晰易读。
myVar=myVar如果myVar为“new”
-请注意,这是python而不是ruby,在布尔上下文等待中,很多东西被认为是错误的。。。为什么要这样做呢?我一直在做Python和Ruby编程的分享,我很难想到一个示例,在这个示例中,您希望使用局部变量实现此功能。当然,您可以将它与Ruby中的一个实例变量一起使用,但这将转换为python中的
thing.foo=thing.foo或'something other'
。你有一个你想在哪里使用它的例子吗?
a | |=blah
的优点是你不必事先准备好值,而且它简单而简短。有点整洁。但我想你是对的。这是在Python中实现这一点的最简单方法。您可以将最后一行缩短为:
a=a,如果a不是其他blah
,或者如果您知道
a
将是真实的
a=a或blah
。当然,这是一个假设,但可能
d.setdefault('a','new')
将是一个更好的选择。我认为get()无法使用全局变量()和局部变量()。在我这样做之后,a仍然没有定义。@科南,我添加的可怕的例子似乎是有效的(只在空闲状态下通过键入stuff进行测试)@JonClements setdefault()确实有效。但是get()似乎有效。使用get()后,我无法访问var<代码>>>>回溯(最近一次调用):文件“”,第1行,名称错误:未定义名称“a”>>>globals().get('a','new')'new'>>回溯(最近一次调用):文件“”,第1行,名称错误:未定义名称“a”
不完全正确。在问题中,a被设置为“无”,然后使用三元表达式将a设置为“新”。如果a为[]或其他任何计算结果为False的值,则编写的三元表达式将失败。如上所述,您需要执行
a不是None
。您是对的,我看错了问题,因此我对其进行了评论,我认为该部分是一个很好的解决方案:)
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!'