如何检查变量是否存在?

1364

我想要检查一个变量是否存在。现在我正在像这样做:

try:
    myVar
except NameError:
    # Do something.

除了使用异常之外,还有其他的方法吗?


24
例外有什么问题? - S.Lott
16
如果myVar是非常复杂的东西,需要很长时间才能生成/评估,那么try语句会不会减慢速度? - abcd
7
@dbliss:这是一个变量。除非你在使用exec或元类进行一些疯狂的操作,否则它不会很昂贵。 - user2357112
1
一个更完整的答案:https://dev59.com/E3I-5IYBdhLWcg3w99kH#1592578 - nickboldt
1
请记住,在Python中,异常本身非常便宜,与Java等语言相比几乎是被鼓励的/符合Python风格。 - ntg
15个回答

2281

检查本地变量是否存在:

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

检查全局变量是否存在:

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

检查一个对象是否具有某个属性:

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

43
好的,我该如何检查类中是否存在属性? - Max Frai
12
如何将可能不存在的变量名转换为字符串? - SilentGhost
20
但是 OP 正在输入代码,他们可以输入 'myVar' 而不是 myVar。如果在编写代码时变量名称未知,它将在运行时存储在字符串变量中,并且我发布的检查也将起作用。 - Ayman Hourieh
10
还有内置变量,如果您有嵌套函数,则存在外部作用域的变量。如果您想检查它们所有,最好还是触发 NameError - Petr Viktorin
23
我最喜欢的是 if hasattr(obj, 'attr_name'): 这个方法,它也适用于类:例如 if hasattr(self, 'attr_name'): - Ron Kalian
显示剩余9条评论

183

使用尚未定义或设置(隐式或显式)的变量通常是不好的,因为它往往表明程序的逻辑并没有完全经过深思熟虑,并且可能导致不可预测的行为。

如果您确实需要在Python中这样做,以下技巧与您的类似,将确保在使用之前变量具有某些值:

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

这样可以确保变量存在,并且只在需要时使用有效的值。

如果您无法控制变量的初始设置,仍然可以添加代码来强制这样做,方法如上所述:

# 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

13
也许它是依赖关系的一个变量,根据版本/平台的不同可能存在或不存在,没有其他方法可以知道它的版本。 - WhyNotHugo
47
状态变量在被赋值之前并不存在。如果你在当前位置和上一个位置之间画一条线,然后将上一个位置设为当前位置,这并不意味着在第一次调用时你“不知道你的变量”。在绘制程序外写入一行额外的代码以初始化previous=null也不能让你更好地“了解你的变量”。 - Dave
36
在任何编程语言中,使用未定义的变量都是不好的。不要用轻蔑的口吻说话。我们中有些人使用Python进行简单的数学或统计脚本,使用类似于Matlab的IDE(如Spyder)工作。在这些环境中,允许用户在全局控制台中定义变量并检查脚本中是否未声明它们有时是有意义的,就像在Matlab中进行数学运算时一样。 - Ricardo Magalhães Cruz
21
@Ricardo,也许你可以考虑一下这可能只是某个知识更加丰富的人所提供的好建议,而不是傲慢的态度。如果我建议不要无限制地使用全局变量、意大利面条式代码、上帝对象、发布未经测试的代码或用COBOL编写操作系统,你是否同样认为这是傲慢的?我的回答解释了我为什么认为这是一个不好的想法(题目中也没有表明OP为什么认为这是必要的),但仍然提供了一种方式,以防他们真的想这样做。 - paxdiablo
6
Python在许多场景中被使用。我正在攻读数学博士学位。在Spyder的环境下,使用Python是有意义的。这就像使用matlab一样。 - Ricardo Magalhães Cruz
显示剩余11条评论

92

一个简单的方法是在一开始初始化它,如下所示:myVar = None

然后稍后:

if myVar is not None:
    # Do something

3
这个答案有很多需要改进的地方。一个简单的方法是先将其声明。`myVar = None

进行操作...

if not myVar: # 为 myVar 赋值 myVar = 'something'`
- Shawn Mehan
1
我非常喜欢这个,因为在我的except语句中,我将事物设置为None。 - Kermit
3
为什么不使用以下代码: if myVar: # Do something这样可以避免阅读双重否定。 - jjisnow
2
@jjisnow 因为您希望即使 myVar 是一个空列表、零、空字符串等,这个条件也应该成立。 - Gabriel
12
如果myVar没有被声明,在Python3中使用if myVar: # Do something会抛出NameError异常。请注意保持翻译准确无误,并尽可能使其通俗易懂,但不要改变原意。 - Agile Bean
显示剩余3条评论

27

使用try/except是测试变量是否存在的最佳方法。但是,几乎肯定有比设置/测试全局变量更好的方法来完成您要做的任何事情。

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

my_variable = None

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

2
我尽量避免使用这个,因为它会污染全局命名空间。避免这种情况的一种方法是将函数作为类,并将我的变量作为类变量,定义 call 作为现有函数的主体,但这很麻烦,也会带来一系列其他问题。我更喜欢使用函数属性,请参见下文。 - samwyse

25

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

'var' in dir(obj)

例如,

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

12

我假设这个测试将被用在一个函数中,类似于user97370的答案。 我不喜欢那个答案,因为它会污染全局命名空间。 修复的一种方法是改用类:

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

9

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


6
处理这种情况的一种常见方法是不显式检查变量是否存在,而是直接在可能不存在的变量的第一次使用中使用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
  ...

6
我已经创建了一个自定义函数。
def exists(var):
     return var in globals()

然后像下面这样调用函数,将variable_name替换为您要检查的变量:

exists("variable_name")

将返回TrueFalse


2
局部变量呢?也许可以让该函数检查局部变量。 - PizzaLovingNerd

3

就像这样:

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))并且最好在定义后加上return True行,这样你就可以写出像assert no('foo')这样更清晰的代码。 - RGD2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接