ChatGPT解决这个技术问题 Extra ChatGPT

如何检查变量是否存在?

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

try:
    myVar
except NameError:
    # Do something.

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

异常有什么问题?
@S.Lott:如果 myVar 真的很复杂,需要很长时间来生成/评估,try 不会减慢速度吗?
@dbliss:这是一个变量。除了一些非常奇怪的情况,如果您对 exec 或元类做一些疯狂的事情,它不会很昂贵。
请记住,与例如 java 相比,python 中的异常本身非常便宜,并且几乎被鼓励/pythonic

A
Ayman Hourieh

检查局部变量是否存在:

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

检查全局变量是否存在:

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

检查对象是否具有属性:

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

好的,我如何检查类中存在的属性?
以及如何将可能不存在的变量名称转换为字符串?
但是 OP 正在输入代码,他们可以输入“myVar”而不是 myVar。如果在写代码的时候不知道变量名,运行时会存储在一个字符串变量中,我贴的check也可以。
还有内置变量,如果您有嵌套函数,还有外部范围内的变量。如果您想检查所有这些,您可能最好还是触发 NameError
我最喜欢的if hasattr(obj, 'attr_name'):也适用于课程:即if hasattr(self, 'attr_name'):
p
paxdiablo

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

如果您需要在 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

也许它是一个依赖变量,根据版本/平台它可能存在也可能不存在,并且没有其他方法可以知道它是什么版本。
状态变量在分配之前不存在 - 如果您从上一个位置到当前位置画一条线,然后设置上一个 = 当前,这并不意味着您在第一次调用时“不知道您的变量”。并且编写额外的代码行来在绘图例程之外初始化 previous=null 并不意味着您“了解您的变量”更好。
我的观点是,“if last: draw(last, current); last=current”块很容易理解,而且编程也不差。添加“try/except”以检查“last”是否存在,然后才能对其进行测试,这会降低该代码的可读性。
“使用尚未定义的变量在任何语言中实际上都是一件坏事” 让我免于居高临下的言论。我们中的一些人使用 Python 编写简单的数学或统计脚本,使用像 Matlab 一样工作的 Spyder 等 IDE。有时在这些环境中允许用户在全局控制台中定义变量并检查它们是否在脚本中未声明(例如在 Matlab 中进行数学运算时)是有意义的。
@Ricardo,也许,而不是假设它是屈尊俯就,您可能想至少考虑一下这可能只是来自可能更有知识的人的好建议:-) 或者,如果我建议不要无限制地使用 global,您是否会认为它同样傲慢变量、意大利面条代码、上帝对象、发布未经测试的代码,还是用 COBOL 编写操作系统?我的回答说明了为什么我认为这是一个坏主意(问题中没有任何内容表明为什么 OP 认为这是必要的),但仍然提供了一种方法,以防他们真的想这样做。
R
Roger Dahl

一个简单的方法是首先初始化它说 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 这避免了阅读双重否定的需要
@jjisnow 因为即使 myVar 是空列表、零、空字符串等,您也希望此条件为真。
如果未声明 myVar,@jjisnow if myVar: # Do something 在 python3 中抛出 NameError
佚名

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

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

my_variable = None

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

我尽量不使用它,因为它会污染全局命名空间。避免这种情况的一种方法是使函数成为一个类,将 my_variable 作为类变量,并将 call 定义为现有函数的主体,但这对编码来说很痛苦,并引发了许多其他问题。我更喜欢使用函数属性,见下文。
W
Wyrmwood

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

'var' in dir(obj)

例如,

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

这真的是答案
C
Community

我将假设测试将在一个函数中使用,类似于 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

S
SilentGhost

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


R
Roger Dahl

处理这种情况的一种通常效果很好的方法是不显式检查变量是否存在,而是继续将可能不存在的变量的第一次使用包装在 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
  ...

P
Psychzander

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

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

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

exists("variable_name")

将返回 TrueFalse


局部变量呢?也许也让该函数检查局部变量。
R
RGD2

像这样:

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') 这样更清晰。
J
James

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

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:

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

这是我的场景:

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 是否是最后一个元素。第二种解决方案在这方面更准确。


OP问“有没有其他方法没有例外?” - 异常缓慢且传播速度慢,因此如果 use_last(i) 引发 UnboundLocalError,您将得到错误的答案并且没有错误消息。也就是说,hasattr 有同样的问题,所以我想这是最“pythonic”的答案。
G
Gulzar

对象也可以使用 __dict__

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

a = A()
assert "m" in a.__dict__
assert "k" not in a.__dict__