【问题标题】:Is there any expression in python that similar to ruby's ||=python中有没有类似于ruby的||=的表达式
【发布时间】:2012-07-19 10:41:20
【问题描述】:

我在 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"

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

【问题讨论】:

  • 请注意,variable ||= value 的通常用法是将默认值设置为已定义的变量,使用它来定义可能存在或可能不存在的变量是恕我直言的不良做法。
  • 我相信,try-except 解决方案是最 Pythonic 的。当然,它不像单个运算符那么简洁,但它清晰易读。
  • myVar = myVar if myVar else "new" - 请注意这是 python 而不是 ruby​​,在布尔上下文中很多东西都被认为是 False
  • 等等...你为什么要这样做?
  • 我一直在做 Python 和 Ruby 编程方面的工作,但我很难想出一个示例,在该示例中您希望使用局部变量来实现此功能。当然,您可以将它与 Ruby 中的实例变量一起使用,但这将转换为 python 为thing.foo = thing.foo or 'something else'。你有一个你想在哪里使用它的例子吗?

标签: python ruby expression


【解决方案1】:

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

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

这样做:

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

【讨论】:

  • a ||= blah的好处是不用事先准备值,简单又简短。这有点整洁。但我想你是对的。这是在 Python 中执行此操作的最简单方法。
  • 您可以将最后几行缩短为:a = a if a is not None else blah,或者如果您知道a 将是真实的a = a or blah
【解决方案2】:

怎么样?

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

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

【讨论】:

  • 不完全。在问题中,将a设置为None,然后使用三元表达式将a设置为“new”。如果 a 是 [] 或其他任何计算结果为 False 的东西,所写的三元表达式将失败。如上所述,你需要做a is not None
  • 你是对的,我读错了问题,因此我对此发表了评论,我说那部分是一个很好的解决方案:)
【解决方案3】:

如果你真的想要这种行为,你最好在 Python 中使用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'

【讨论】:

  • 当然,这是一个假设,但d.setdefault('a', 'new') 可能是更好的选择。
  • 我认为 get() 不能与 globals() 和 locals() 一起使用。在我这样做之后,a 仍然没有定义。
  • @conan 好吧,我添加的可怕示例似乎有效(仅在 IDLE 中输入内容进行测试)
  • @JonClements setdefault() 确实有效。但 get() 似乎工作。使用 get() 后我无法访问 var。 &gt;&gt;&gt; a Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; NameError: name 'a' is not defined &gt;&gt;&gt; globals().get('a', 'new') 'new' &gt;&gt;&gt; a Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; NameError: name 'a' is not defined
【解决方案4】:

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

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

没事

【讨论】:

    【解决方案5】:

    考虑使用非常 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's lru cache

    【讨论】:

      【解决方案6】:

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

      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 声明它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-09
        • 1970-01-01
        • 2010-09-28
        • 2021-09-17
        相关资源
        最近更新 更多