我想检查变量是否存在。现在我正在做这样的事情:
try:
myVar
except NameError:
# Do something.
有没有其他方法没有例外?
myVar
真的很复杂,需要很长时间来生成/评估,try
不会减慢速度吗?
exec
或元类做一些疯狂的事情,它不会很昂贵。
检查局部变量是否存在:
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
是 意味着 在评论代码中做的(但没有),如果你仍然可以将代码添加到 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
一个简单的方法是首先初始化它说 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
这避免了阅读双重否定的需要
myVar
是空列表、零、空字符串等,您也希望此条件为真。
if myVar: # Do something
在 python3 中抛出 NameError
使用 try/except 是测试变量是否存在的最佳方法。但几乎可以肯定,除了设置/测试全局变量之外,你正在做的任何事情都有更好的方法。
例如,如果你想在第一次调用某个函数时初始化一个模块级变量,你最好使用如下代码:
my_variable = None
def InitMyVariable():
global my_variable
if my_variable is None:
my_variable = ...
对于对象/模块,您还可以
'var' in dir(obj)
例如,
>>> class Something(object):
... pass
...
>>> c = Something()
>>> c.a = 1
>>> 'a' in dir(c)
True
>>> 'b' in dir(c)
False
我将假设测试将在一个函数中使用,类似于 user97370's answer。我不喜欢这个答案,因为它污染了全局命名空间。解决它的一种方法是改用一个类:
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
处理这种情况的一种通常效果很好的方法是不显式检查变量是否存在,而是继续将可能不存在的变量的第一次使用包装在 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
...
我创建了一个自定义函数。
def exists(var):
return var in globals()
然后调用函数,如下所示,将 variable_name
替换为您要检查的变量:
exists("variable_name")
将返回 True
或 False
像这样:
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:
__builtins__
的行应该替换为: import builtins assert( var not in vars(builtins)) 用 return True
行完成定义可能不是一个坏习惯,所以你可以写东西像 assert no('foo')
这样更清晰。
它可能不是高性能的,但您将解决方案推广到一个检查局部变量和全局变量的函数。
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')
短变体:
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.
我无法轻易确定 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
是否是最后一个元素。第二种解决方案在这方面更准确。
use_last(i)
引发 UnboundLocalError
,您将得到错误的答案并且没有错误消息。也就是说,hasattr
有同样的问题,所以我想这是最“pythonic”的答案。
对象也可以使用 __dict__
。
class A(object):
def __init__(self):
self.m = 1
a = A()
assert "m" in a.__dict__
assert "k" not in a.__dict__
不定期副业成功案例分享
NameError
。if hasattr(obj, 'attr_name'):
也适用于课程:即if hasattr(self, 'attr_name'):