【问题标题】:How do I check if a variable exists?如何检查变量是否存在?
【发布时间】:2010-10-25 00:05:21
【问题描述】:

我想检查一个变量是否存在。现在我正在做这样的事情:

try:
   myVar
except NameError:
   # Do something.

还有没有例外的方法?

【问题讨论】:

  • 异常有什么问题?
  • @S.Lott:如果myVar 真的很复杂,需要很长时间来生成/评估,try 不会减慢速度吗?
  • @dbliss:这是一个变量。除了一些非常奇怪的情况,如果你对 exec 或元类做一些疯狂的事情,它不会很昂贵。
  • 请记住,与例如异常相比,python 中的异常本身非常便宜。 java和几乎被鼓励/pythonic

标签: python exception variables


【解决方案1】:

它可能不是高性能的,但您将解决方案推广到一个同时检查局部变量和全局变量的函数。

import inspect
def exists_var(var_name):
    frame = inspect.currentframe()
    try:
        return var_name in frame.f_back.f_locals or var_name in globals()
    finally:
        del frame

那么你可以这样使用它:

exists_var('myVar')

【讨论】:

    【解决方案2】:

    对象也可以使用__dict__

    class A(object):
        def __init__(self):
            self.m = 1
    
    a = A()
    assert "m" in a.__dict__
    assert "k" not in a.__dict__
    

    【讨论】:

      【解决方案3】:

      任何语言中使用尚未定义或设置(隐式或显式)的变量通常是一件坏事,因为它往往表明程序的逻辑还没有考虑周全,可能会导致不可预知的行为。

      如果您需要在 Python 中执行此操作,则与您的类似的以下技巧将确保变量在使用前具有 some 值:

      try:
          myVar
      except NameError:
          myVar = None      # or some other default value.
      
      # Now you're free to use myVar without Python complaining.
      

      但是,我仍然不相信这是一个好主意 - 在我看来,您应该尝试重构您的代码,以免发生这种情况。

      作为示例,下面的注释中给出了以下代码,以允许从前一点到当前点绘制线条:

      if last:
          draw(last, current);
      last = current
      

      如果last 没有绑定到一个值,这在Python 中根本没有帮助,因为即使是last检查 也会引发异常。一个更好的主意是确保last 确实 有一个值,可以用来决定它是否有效。那将是这样的:

      last = None
      
      # some time passes ...
      
      if last is not None:
          draw(last, current);
      last = current
      

      这样可以确保变量存在,并且只有在它对您需要的目的有效时才使用它。这就是我假设 if last 意味着 在评论代码中做的(但没有),如果你仍然可以将代码添加到 force无法控制变量的初始设置,使用上面的异常方法:

      # Variable 'last' may or may not be bound to a value at this point.
      
      try:
          last
      except NameError:
          last = None
      
      # It will always now be bound to a value at this point.
      
      if last is not None:
          draw(last, current);
      last = current
      

      【讨论】:

      • 也许它是一个依赖变量,根据版本/平台它可能存在也可能不存在,没有其他方法可以知道它是什么版本。
      • 状态变量在赋值之前是不存在的——如果你从前一个位置画一条线到当前位置,然后设置previous = current,并不代表你“不知道”你的变量”在第一次通话。在绘图例程之外编写额外的代码行来初始化 previous=null 并不意味着您“更了解变量”。
      • 我的意思是,“if last: draw(last, current); last=current” 块很容易理解,编程也不差。添加“try/except”来检查“last”是否存在,然后才能对其进行测试,这会降低该代码的可读性。
      • “在任何语言中使用尚未定义的变量实际上都是一件坏事” 让我不要居高临下的话。我们中的一些人使用 Python 编写简单的数学或统计脚本,使用像 Matlab 一样工作的 Spyder 等 IDE。在这些环境中,有时允许用户在全局控制台中定义变量并检查它们是否在脚本中未声明(例如在 Matlab 中进行数学运算时)是有意义的。
      • @Ricardo,也许,与其假设这是屈尊俯就,您可能希望至少考虑这只是来自可能的人的好建议> 知识渊博 :-) 或者,如果我建议不要无限制地使用全局变量、意大利面条代码、上帝对象、发布未经测试的代码或用 COBOL 编写操作系统,您会认为这同样是光顾吗?我的回答说明了为什么我认为这是一个坏主意(问题中没有任何内容表明为什么 OP 认为这是必要的),但仍然提供了一种方法,以防他们真的想这样做。
      【解决方案4】:

      像这样:

      def no(var):
          "give var as a string (quote it like 'var')"
          assert(var not in vars())
          assert(var not in globals())
          assert(var not in vars(__builtins__))
          import keyword
          assert(var not in keyword.kwlist)
      

      然后:

      no('foo')
      foo = ....
      

      如果你的新变量foo 使用不安全,你会得到一个AssertionError 异常,它会指向失败的行,然后你会知道得更好。 这是明显的人为的自我引用:

      no('no')
      
      ---------------------------------------------------------------------------
      AssertionError                            Traceback (most recent call last)
      <ipython-input-88-d14ecc6b025a> in <module>
      ----> 1 no('no')
      
      <ipython-input-86-888a9df72be0> in no(var)
            2     "give var as a string (quote it)"
            3     assert( var not in vars())
      ----> 4     assert( var not in globals())
            5     assert( var not in vars(__builtins__))
            6     import keyword
      
      AssertionError: 
      

      【讨论】:

      • 在 python3 中,__builtins__ 的行应替换为: import builtins assert( var not in vars(builtins)) 用@987654327 完成定义可能不是一个坏习惯@ 行,这样你就可以写像assert no('foo') 这样更清晰的东西。
      【解决方案5】:

      这是我的场景:

      for i in generate_numbers():
          do_something(i)
      # Use the last i.
      

      我无法轻易确定 length of the iterable,这意味着 i 可能存在也可能不存在,具体取决于可迭代对象是否产生空序列。

      如果我想使用可迭代对象的最后一个 i(一个空序列不存在的 i),我可以做以下两件事之一:

      i = None  # Declare the variable.
      for i in generate_numbers():
          do_something(i)
      use_last(i)
      

      for i in generate_numbers():
          do_something(i)
      try:
          use_last(i)
      except UnboundLocalError:
          pass  # i didn’t exist because sequence was empty.
      

      第一个解决方案可能有问题,因为我无法判断(取决于序列值)i 是否是最后一个元素。第二种解决方案在这方面更准确。

      【讨论】:

      • OP问“有没有其他方法没有例外?” - 异常很慢并且会传播,所以如果use_last(i) 引发UnboundLocalError,你会得到错误的答案并且没有错误消息。也就是说,hasattr 有同样的问题,所以我想这是最“pythonic”的答案。
      【解决方案6】:

      短变体:

      my_var = some_value if 'my_var' not in globals() else my_var:
      

      【讨论】:

      • 这对于我们在 Databricks 中遇到的用例很有用。对于详细的程序来说,这不是一个很好的系统,因为从另一个笔记本运行一个笔记本会破坏任何相同的命名变量。要减少破坏,请使用预先存在的值(如果存在)
      【解决方案7】:

      我创建了一个自定义函数。

      def exists(var):
           return var in globals()
      

      然后调用函数,如下所示,将 variable_name 替换为您要检查的变量:

      exists("variable_name")
      

      将返回TrueFalse

      【讨论】:

      • 局部变量呢?也许也可以让该函数检查局部变量。
      【解决方案8】:

      一个简单的方法是首先初始化它说myVar = None

      然后:

      if myVar is not None:
          # Do something
      

      【讨论】:

      • 这个答案有很多需要改进的地方。相反 - 一个简单的方法是首先声明它。 myVar = none # do stuff... if not myVar: # give myVar a value myVar = 'something'
      • 我非常喜欢这个,因为我在 except 语句中将事情设置为 None
      • 为什么不像:if myVar: # Do something 这样可以避免阅读双重否定
      • @jjisnow 因为即使myVar 是空列表、零、空字符串等,您也希望此条件为真。
      • @jjisnow if myVar: # Do something 如果未声明 myVar,则在 python3 中抛出 NameError
      【解决方案9】:

      我将假设测试将在一个函数中使用,类似于user97370's answer。我不喜欢这个答案,因为它污染了全局命名空间。解决它的一种方法是改用一个类:

      class InitMyVariable(object):
        my_variable = None
      
      def __call__(self):
        if self.my_variable is None:
         self.my_variable = ...
      

      我不喜欢这样,因为它使代码复杂化并引发了一些问题,例如,这是否符合单例编程模式?幸运的是,Python 允许函数有属性有一段时间了,这给了我们这个简单的解决方案:

      def InitMyVariable():
        if InitMyVariable.my_variable is None:
          InitMyVariable.my_variable = ...
      InitMyVariable.my_variable = None
      

      【讨论】:

        【解决方案10】:

        对于对象/模块,你也可以

        'var' in dir(obj)
        

        例如,

        >>> class Something(object):
        ...     pass
        ...
        >>> c = Something()
        >>> c.a = 1
        >>> 'a' in dir(c)
        True
        >>> 'b' in dir(c)
        False
        

        【讨论】:

          【解决方案11】:

          处理这种情况通常很有效的一种方法是不显式检查变量是否存在,而是继续将可能不存在的变量的第一次使用包装在 try/except NameError 中:

          # Search for entry.
          for x in y:
            if x == 3:
              found = x
          
          # Work with found entry.
          try:
            print('Found: {0}'.format(found))
          except NameError:
            print('Not found')
          else:
            # Handle rest of Found case here
            ...
          

          【讨论】:

            【解决方案12】:

            catch 在 Python 中被称为 except。除此之外,对于这种简单的情况很好。 AttributeError 可用于检查对象是否具有属性。

            【讨论】:

              【解决方案13】:

              使用 try/except 是测试变量是否存在的最佳方法。但几乎可以肯定,除了设置/测试全局变量之外,还有更好的方法来做您正在做的事情。

              例如,如果你想在第一次调用某个函数时初始化一个模块级变量,你最好使用如下代码:

              my_variable = None
              
              def InitMyVariable():
                global my_variable
                if my_variable is None:
                  my_variable = ...
              

              【讨论】:

              • 我尽量不使用这个,因为它污染了全局命名空间。避免这种情况的一种方法是使函数成为一个类,将 my_variable 作为类变量,并将 call 定义为现有函数的主体,但这很麻烦,而且会打开一堆其他问题。我更喜欢使用函数属性,见下文。
              【解决方案14】:

              检查局部变量是否存在:

              if 'myVar' in locals():
                # myVar exists.
              

              检查全局变量是否存在:

              if 'myVar' in globals():
                # myVar exists.
              

              检查对象是否具有属性:

              if hasattr(obj, 'attr_name'):
                # obj.attr_name exists.
              

              【讨论】:

              • 好的,我如何检查类中存在的属性?
              • 你如何将可能不存在的变量名变成字符串?
              • 但是 OP 正在输入代码,他们可以输入 'myVar' 而不是 myVar。如果写代码的时候不知道变量名,运行时会存储在一个字符串变量中,我贴的check也行。
              • 还有内置变量,如果你有嵌套函数,还有外部作用域中的变量。如果你想检查所有这些,你可能最好还是触发NameError
              • 我最喜欢if hasattr(obj, 'attr_name'):,它也适用于课程:即if hasattr(self, 'attr_name'):
              猜你喜欢
              • 2018-02-17
              • 1970-01-01
              • 2014-09-08
              • 2014-01-30
              • 2012-07-05
              • 2018-08-13
              • 2011-08-18
              相关资源
              最近更新 更多