Python中如何确定变量是否已定义

544
如何在运行时知道代码中的特定位置是否设置了变量?这并不总是明显的,因为(1)变量可能在有条件的情况下被设置,而且(2)变量可能会被有条件地删除。我正在寻找像Perl中的defined()、PHP中的isset()或Ruby中的defined?这样的东西。
if condition:
    a = 42

# is "a" defined here?

if other_condition:
    del a

# is "a" defined here?

12
重复内容:https://dev59.com/UXRA5IYBdhLWcg3wvgob,https://dev59.com/33RB5IYBdhLWcg3wAjNH。这些问题都在讨论如何检查 Python 变量是否已定义。 - carl
90
请不要“有条件地”设置变量,这是可怕的糟糕设计。请始终考虑到所有逻辑路径,不要继续这样做。 - S.Lott
2
+1 给 S.Lott 的回答。有办法做某事并不意味着在新项目中应该使用它。 - Bite code
10
@S.Lott:我不得不反对。当我使用import来“导入”一个“配置文件”(即只包含赋值的文件)时,可能会出现某些变量未在其中定义的情况。而且对于我来说,importConfigParser更便宜/简单,因此实用主义在这里胜过美观。 - 0xC0000022L
17
@STATUS_ACCESS_DENIED:这就是默认值适用的情况。首先设置默认值,然后导入配置文件。现在所有变量都已定义,无论是默认值还是在配置文件中覆盖的值。您可以轻松地避免有条件地设置变量。 - S.Lott
显示剩余4条评论
6个回答

780
try:
    thevariable
except NameError:
    print("well, it WASN'T defined after all!")
else:
    print("sure, it was defined.")

79
@Aaron:有许多情况下,您不知道变量是否定义。您可以在许多情况下重构代码以避免这种情况,但并非所有情况都适用。Alex的解决方案是正确的,并且在某些情况下无法进行重构时是最佳选择。由于问题中没有太多信息,因此我认为只有提出问题的人才能选择处理他的情况的最佳方法。 - Denis Otkidach
148
@Aaron,“should”这个词是一个四字母词--例如,没有司机“应该”超速行驶,但这并不意味着你不会采取所有必要的预防措施来对抗那些仍然这样做的人。维护脆弱、未经充分测试的遗留代码,这些代码设计有点问题,而且你是从别人那里继承下来的,这是生活中的一个事实。那些只能想到从头开始全面重写而不是小心谨慎地逐步修改的人需要重新阅读Joel九年前的文章http://www.joelonsoftware.com/articles/fog0000000069.html 。 - Alex Martelli
24
这场辩论比答案本身更有趣,顺便说一下,答案是100%正确的,能够让你优雅地处理糟糕的遗留代码。 - Bite code
16
例外应该保留给非常特殊的情况,而不是作为“if”的孪生兄弟来滥用 :-( - einpoklum
22
在几乎每一个for循环语句中,Python会使用异常StopIteration来表示迭代器已经完成了所有操作。当然,迭代结束并不是一个“异常情况”——事实上,大多数迭代都是期望终止的。因此,显然,你对异常使用的意见并不适用于Python(其他编程语言有着不同的实用性,所以与你提到的问题一样,“通用语言”并不适用于这个问题)。 - Alex Martelli
显示剩余16条评论

460

'a' in vars() or 'a' in globals()

如果你想要严谨一点,你还可以检查内置函数
'a' in vars(__builtins__)


36
我相信这应该是答案。请参见https://dev59.com/UXRA5IYBdhLWcg3wvgob - 0atman
3
这是一个非常习惯用语的答案。这里有一个很好的使用场景,可以使用映射;例如,if "prop2" in {"prop0": None, "prop1": None}: - robert
3
截至今天—— 2018年6月:我认为 vars(__builtin__) 在 Python 2 或 3 中都不再可用。我相信现在应该使用 vars(__builtins__) (注意复数)适用于两个版本(已在 Python 2.7.10 和 Python 3.6.1 上测试)。 - user8554766
2
为什么不使用locals(),为什么不使用dir()? - AndresVia
2
@AndresVia globals()locals() 的超集。 - KeyC0de
显示剩余3条评论

166

我认为最好避免这种情况。写成下面这样会更加清晰简洁:

a = None
if condition:
    a = 42

9
如果您希望以这种方式进行操作,您应该使初始值唯一,以便可以将其与将a设置为None的情况区分开来,例如UNDEFINED=object();a=UNDEFINED,然后您可以使用a is not UNDEFINED 进行测试。 - John La Rooy
19
这是None的常见用法。它字面上的语义意思就是“没有”,什么也没有,没有价值。它存在,但是“没有值”。如果在赋值等情况中可能出现None,使用非None值是有用的,但这并不像避免使用None那样普遍。例如,在问题中,变量a只会是42或未定义的。将未定义更改为具有None值不会丢失任何信息。 - Devin Jeanpierre
6
这是正确的方式,不确定为什么有些人会使用冗长而混乱的try/except结构来完成这个任务。此外,当在类成员函数中使用关键字参数且不想硬编码默认值到参数列表时,这非常有用(只需将默认值定义为类成员)。 - FizxMike
1
@DevinJeanpierre 这并不一定是正确的。如果你想为一个JSON API创建一些客户端库,这个API将null值视为与未指定的值不同(例如,None将实际的JSON值设置为null,而未指定则完全省略它,这使得API使用默认值或从其他属性计算),那么你需要区分NoneUndefined,或者None和JSON null。认为None不能或不应该与明确未指定或未定义的值有所不同是非常短视的。 - Taywee
9
提供默认值(这就是本回答所做的)与测试变量的存在远不相同。 在使用情况上可能会有很大的重叠,但如果您想查看某个变量是否已定义,使用此方法将永远无法知道。 - Tim S.
显示剩余2条评论

25
try:
    a # does a exist in the current namespace
except NameError:
    a = 10 # nope

11
异常情况下才应使用异常。请参阅此讨论 - einpoklum
22
对于大多数编程语言来说这是真的,但在Python中异常更为常见,例如请参考 https://dev59.com/_XA75IYBdhLWcg3w0sl9 - sdcvvc
4
嗯,看起来很奇怪但却是真的。我仍然认为那不是个好主意商标,但是,嘛,也无法反驳社区规矩。 - einpoklum
3
最好使用上面提到的 if 'a' in vars() or 'a' in globals() 解决方案,这种解决方案不需要使用异常。 - Ron Kalian
1
尝试/捕获是在Python中常用的操作。在一种语言中被称为代码异味的特征,在另一种语言中可能被视为一项功能。 - eric
Python 绝对鼓励您更频繁地使用异常。在许多情况下,您不应该专门检查操作是否可行,而是应该捕获异常。通过确保仅捕获您预期的异常类型来实现清晰明了的代码。上述答案是一个很好的 Pythonic 解决方案。(此外,Python 中的异常成本低廉,开销小) - Chris

6

在这种情况下,最好使用a = None而不是del a。这将减少对象a的引用计数(如果有任何分配),并且当a未定义时不会失败。请注意,del语句不直接调用对象的析构函数,而是将其从变量中解绑。当引用计数为零时,对象的析构函数被调用。


5

可能需要使用此功能的一种情况:

如果您在try块中使用finally块来关闭连接,但程序在定义连接之前用sys.exit()退出,则finally块将被调用并且连接关闭语句将失败,因为没有创建连接。


1
那么也许连接关闭不应该在 finally 中完成? - Mawg says reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接