我想检查变量是否存在。现在我在做这样的事情:
try:
myVar
except NameError:
# Do something.
有没有其他没有例外的方法?
我想检查变量是否存在。现在我在做这样的事情:
try:
myVar
except NameError:
# Do something.
有没有其他没有例外的方法?
查询一个局部变量是否存在。
if 'myVar' in locals():
# myVar exists.
检查全局变量是否存在:
if 'myVar' in globals():
# myVar exists.
检查一个对象是否有属性:
if hasattr(obj, 'attr_name'):
# obj.attr_name exists.
在任何语言中,使用尚未定义或设置(隐式或显式)的变量通常都是一件坏事,因为它往往表明程序的逻辑没有经过适当的考虑,并可能导致不可预测的行为。
如果你需要在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
这确保了变量的存在,并且只在它对需要它的目的有效时才使用它。这就是我假设if last在注释代码中要做的事情(但没有),如果你无法控制变量的初始设置,你仍然可以添加代码来强制执行,使用上面的exception方法:
# 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
使用try/except是测试变量是否存在的最佳方法。但是几乎可以肯定有比设置/测试全局变量更好的方法。
例如,如果你想在第一次调用某个函数时初始化一个模块级变量,你最好使用这样的代码:
my_variable = None
def InitMyVariable():
global my_variable
if my_variable is None:
my_variable = ...
处理这种情况的一种方法通常是不显式检查变量是否存在,而是直接将可能不存在的变量的第一次使用包装在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
...
我将假设测试将用于一个函数中,类似于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
对于对象/模块,也可以
'var' in dir(obj)
例如,
>>> class Something(object):
... pass
...
>>> c = Something()
>>> c.a = 1
>>> 'a' in dir(c)
True
>>> 'b' in dir(c)
False
我创建了一个自定义函数。
def exists(var):
return var in globals()
然后调用函数,将variable_name替换为你想检查的变量:
exists("variable_name")
将返回True或False
这是我的设想:
for i in generate_numbers():
do_something(i)
# Use the last i.
我不能轻易确定迭代对象的长度,这意味着I可能存在,也可能不存在,这取决于迭代对象是否产生一个空序列。
如果我想使用iterable的最后一个I(一个空序列不存在的I),我可以做以下两件事之一:
i = None # Declare the variable.
for i in generate_numbers():
do_something(i)
use_last(i)
or
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 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:
对象也可以使用__dict__。
class A(object):
def __init__(self):
self.m = 1
a = A()
assert "m" in a.__dict__
assert "k" not in a.__dict__
它可能不是高性能的,但您将解决方案泛化为一个同时检查局部变量和全局变量的函数。
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')