如何检查变量是否存在?

How do I check if a variable exists?

提问人:Max Frai 提问时间:5/9/2009 最后编辑:Mateen UlhaqMax Frai 更新时间:5/22/2023 访问量:1702096

问:

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

try:
    myVar
except NameError:
    # Do something.

有没有其他方法无一例外?

Python 异常 变量

评论

24赞 S.Lott 5/9/2009
例外有什么问题?
16赞 abcd 4/9/2015
@S.Lott:如果某件事真的很复杂,需要很长时间来制作/评估,那会不会减慢速度?myVartry
7赞 user2357112 9/13/2016
@dbliss:这是一个变量。除了一些非常奇怪的情况,如果你正在做一些疯狂的事情或元类,它不会很昂贵。exec
1赞 nickboldt 9/30/2016
一个更完整的答案:stackoverflow.com/a/1592578/1661797
1赞 ntg 10/2/2021
请记住,与.java Java相比,Python中的异常本身非常便宜,并且几乎被鼓励/ pythonic

答:

9赞 SilentGhost 5/9/2009 #1

catch在 Python 中被调用,但 except 在 Python 中。除此之外,对于这种简单的情况也没关系。AttributeError 可用于检查对象是否具有属性。

2284赞 Ayman Hourieh 5/9/2009 #2

要检查局部变量是否存在:

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

要检查全局变量是否存在:

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

要检查对象是否具有属性,请执行以下操作:

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

评论

43赞 Max Frai 5/9/2009
好的,我该如何检查类中存在的属性?
12赞 SilentGhost 5/9/2009
以及如何将可能不存在的变量名称转换为字符串?
20赞 Ayman Hourieh 5/9/2009
但是 OP 正在输入代码,他们可以键入 myVar 的 'myVar' intstead。如果在编写代码时不知道变量名称,则在运行时将其存储在字符串变量中,并且我发布的检查也将起作用。
10赞 Petr Viktorin 6/11/2014
还有内置变量,如果您有嵌套函数,则还有外部作用域中的变量。如果你想检查所有这些,你可能最好还是触发。NameError
23赞 Ron Kalian 10/30/2017
我最喜欢它也适用于课堂:即if hasattr(obj, 'attr_name'):if hasattr(self, 'attr_name'):
184赞 paxdiablo 5/9/2009 #3

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

如果你确实需要在 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

在未绑定到值的情况下,这在 Python 中根本无济于事,因为即使检查也会引发异常。一个更好的主意是确保确实有一个值,一个可以用来决定它是否有效的值。这将是这样的:lastlastlast

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 2/14/2012
也许它是一个依赖变量,根据版本/平台,它可能存在也可能不存在,并且没有其他方法可以知道它是什么版本。
47赞 Dave 8/26/2012
状态变量在赋值之前并不存在 - 如果你从前一个位置到当前位置画一条线,然后设置 previous = current,这并不意味着你在第一次调用时“不知道你的变量”。在绘制例程之外编写一行额外的代码来初始化 previous=null 并不意味着您“更了解您的变量”。
6赞 Dave 8/27/2012
我的观点是,一个块“if last: draw(last, current);last=current“很容易理解,而不是糟糕的编程。在能够测试“last”之前添加“try/except”来检查“last”是否存在会降低该代码的可读性。
36赞 Ricardo Magalhães Cruz 12/28/2015
“使用尚未定义的变量在任何语言中实际上都是一件坏事”请原谅我居高临下的演讲。我们中的一些人使用 Python 进行简单的数学或统计脚本,使用 IDE(如 Spyder)工作方式类似于 Matlab。在这些环境中,有时允许用户在全局控制台中定义变量并检查它们是否在脚本中未声明,例如在 Matlab 中进行数学运算时,这是有意义的。
21赞 paxdiablo 12/28/2015
@Ricardo,也许,与其假设这是居高临下,不如至少考虑一下这只是来自知识渊博的人的好建议的可能性:-)或者,如果我建议不要无限制地使用全局变量、意大利面条代码、上帝对象、发布未经测试的代码或用 COBOL 编写操作系统,您会认为这同样是居高临下吗?我的回答说明了为什么我认为这是一个坏主意(问题中没有任何内容表明为什么 OP 认为这是必要的),但仍然提供了一种他们真正想这样做的方法。
27赞 user97370 5/9/2009 #4

使用 try/except 是测试变量是否存在的最佳方法。但几乎可以肯定的是,有一种比设置/测试全局变量更好的方法来做你正在做的事情。

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

my_variable = None

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

评论

2赞 samwyse 3/25/2014
我尽量不使用它,因为它会污染全局命名空间。避免这种情况的一种方法是将函数设为类,将 my_variable 作为类变量,并将 call 定义为现有函数的主体,但这对编码来说很痛苦,并引发了一堆其他问题。我更喜欢使用函数属性,见下文。
6赞 Roger Dahl 9/8/2010 #5

处理这种情况的一种方法通常是不显式检查变量是否存在,而是继续将可能不存在的变量的第一次用法包装在 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赞 samwyse 3/26/2014 #6

我将假设该测试将用于一个函数中,类似于 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
25赞 Wyrmwood 10/29/2014 #7

对于对象/模块,您还可以

'var' in dir(obj)

例如

>>> class Something(object):
...     pass
...
>>> c = Something()
>>> c.a = 1
>>> 'a' in dir(c)
True
>>> 'b' in dir(c)
False
92赞 Chinedum Ukejianya 6/5/2015 #8

一个简单的方法是在第一次说的时候初始化它myVar = None

然后稍后:

if myVar is not None:
    # Do something

评论

3赞 Shawn Mehan 11/26/2015
这个答案有很多需要改进的地方。相反 - 一个简单的方法是先声明它。myVar = none # do stuff... if not myVar: # give myVar a value myVar = 'something'
1赞 Kermit 7/6/2018
我非常喜欢这个,因为我在我的语句中将内容设置为 Noneexcept
3赞 jjisnow 7/9/2018
为什么不是这样的: 这样就避免了阅读双重否定的需要if myVar: # Do something
2赞 Gabriel 7/28/2018
@jjisnow 因为你希望这个条件是真的,即使是一个空列表、零、空字符串等。myVar
13赞 Agile Bean 7/31/2018
如果未声明 myVar,@jjisnow会抛出 python3if myVar: # Do somethingNameError
6赞 Abhishek R 1/31/2020 #9

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

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

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

exists("variable_name")

将返回或TrueFalse

评论

2赞 PizzaLovingNerd 9/7/2020
局部变量呢?也许让该函数也检查局部变量。
1赞 Давид Шико 8/6/2020 #10

短款:

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

评论

0赞 pauljohn32 11/22/2021
这对于我们在 Databricks 中遇到的用例非常有用。对于详细程序来说,它不是一个很好的系统,因为从一个笔记本运行另一个笔记本会破坏任何相同的命名变量。要减少损坏,请使用预先存在的值(如果存在)
0赞 Jens 9/16/2020 #11

这是我的场景:

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

我无法轻易确定可迭代对象的长度,这意味着它可能存在,也可能不存在,这取决于可迭代对象是否产生空序列。i

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

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

评论

0赞 c z 12/9/2020
OP 问道:“有没有其他方法没有例外? - 异常速度很慢且会传播,所以如果引发,你会得到错误的答案,并且没有错误消息。也就是说,有同样的问题,所以我想这是最“pythonic”的答案。use_last(i)UnboundLocalErrorhasattr
3赞 RGD2 2/22/2021 #12

这样:

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 = ....

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

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: 

评论

0赞 RGD2 4/1/2021
在 python3 中,with 行应替换为: import builtins assert( var not in vars(builtins)) 用一行完成定义可能不是一个坏习惯,这样你就可以写出更清晰的东西。__builtins__return Trueassert no('foo')
0赞 Gulzar 6/8/2021 #13

对于对象,也是一种可能性,使用.__dict__

class A(object):
    def __init__(self):
        self.m = 1

a = A()
assert "m" in a.__dict__
assert "k" not in a.__dict__
2赞 James 6/10/2021 #14

它可能不具有性能,但您可以将解决方案推广为同时检查局部变量和全局变量的函数。

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')
0赞 Mihai.Mehe 5/13/2023 #15

简单的一行:

a=1
exec("try: a \nexcept NameError: print('Does not exist.')\nelse:print(a)")

并做一些事情:

exec("def my_try(): \n\ttry: a \n\texcept NameError: print('Does not exist.Creating a=');a=1;print(a);\n\telse:print(a)\n\n\nmy_try()")