如何检查变量是否存在?

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

try:myVarexcept NameError:# Do something.

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

1522851 次浏览

catch在Python中被称为#1。除此之外,对于这种简单的情况也没问题。有#2可用于检查对象是否具有属性。

检查局部变量的存在:

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

检查全局变量的存在:

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

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

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

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

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

try:myVarexcept 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在注释代码中是意味着要做的(但没有),如果你无法控制变量的初始设置,你仍然可以将代码添加到,使用上面的异常方法:

# Variable 'last' may or may not be bound to a value at this point.
try:lastexcept 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

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

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

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

处理这种情况的一种通常有效的方法是不明确检查变量是否存在,而是继续将可能不存在的变量的第一次使用包装在try/除外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...

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

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

我不喜欢这样,因为它使代码复杂化并引发诸如这是否应该确认Singleton编程模式之类的问题?幸运的是,Python已经允许函数具有属性一段时间了,这给了我们这个简单的解决方案:

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

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

'var' in dir(obj)

例如,

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

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

然后是:

if myVar is not None:# Do something

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

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

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

exists("variable_name")

将返回TrueFalse

短变体:

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

这是我的场景:

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

我不能很容易地确定迭代的长度,这意味着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是否是最后一个元素。第二个解决方案在这方面更准确。

像这样:

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 keywordassert(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:

对于对象,也可以使用__dict__

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

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

import inspectdef 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')