Python无比较:我应该使用“is”还是==?
Posted
技术标签:
【中文标题】Python无比较:我应该使用“is”还是==?【英文标题】:Python None comparison: should I use "is" or ==? 【发布时间】:2012-12-24 05:13:30 【问题描述】:当我比较 my_var == None
时,我的编辑器会警告我,但当我使用 my_var is None
时没有警告。
我在 Python shell 中进行了测试,并确定两者都是有效的语法,但我的编辑器似乎说my_var is None
是首选。
是这样吗,如果是,为什么?
【问题讨论】:
PEP 8 在某处说您应该使用is
- python.org/dev/peps/pep-0008/#programming-recommendations 与单身人士进行比较
那张海报在谈论 Python 3,而我的问题是关于 Python 2.x。我不确定这是否有足够大的差异来保证两者都保留,但我编辑了问题以包含它以防万一。
我不认为这个问题真的是重复的。另一个是关于 == vs is in general,这个是关于 None 特别是。
【参考方案1】:
总结:
当您想要检查对象的身份时使用is
(例如检查var
是否为None
)。当您想检查相等性时使用==
(例如var
是否等于3
?)。
说明:
您可以有自定义类,my_var == None
将返回 True
例如:
class Negator(object):
def __eq__(self,other):
return not other
thing = Negator()
print thing == None #True
print thing is None #False
is
检查对象身份。只有 1 个对象 None
,所以当您执行 my_var is None
时,您正在检查它们是否实际上是同一个对象(不仅仅是 等效 对象)
换句话说,==
是对等价的检查(由对象到对象定义),而is
检查对象身份:
lst = [1,2,3]
lst == lst[:] # This is True since the lists are "equivalent"
lst is lst[:] # This is False since they're actually different objects
【讨论】:
is None
与 == None
何时不同?
@Blender 在提到的情况下。 __eq__
可以用任何方式定义,但is
的行为不能轻易改变。
@LevLevitsky:Mython 的示例用途之一是“扩展协议,以便任何运算符都可以重载,甚至 is
”。在对列表发表评论后,他将其更改为“……即使是is
(但前提是你疯了)。”
+1,但如果这个答案包括其他人所做的 PEP 8 参考会更好(以及解释为什么 PEP 8 背后的决定是有意义的,它已经这样做了)。
@abarnert -- 我什至不知道 PEP 8 在这里提出了建议。关键是他们是不同的操作员,做不同的事情。在某些情况下,object == None
实际上 is 是正确的成语(尽管我想不出任何想法)。你只需要知道你在做什么。【参考方案2】:
is
在将任意对象与像None
这样的单例对象进行比较时通常首选,因为它更快且更可预测。 is
总是按对象身份进行比较,而 ==
将做什么取决于操作数的确切类型,甚至取决于它们的顺序。
此建议得到PEP 8 的支持,explicitly states 表示“应始终使用is
或is not
与单例进行比较,而不应使用相等运算符。”
【讨论】:
感谢您发布此信息;接受的答案提出了一些有趣的观点,但你的回答更直接。 依赖本质上是实现细节的东西似乎很奇怪。为什么我要关心有多少个 NoneType 实例? @BallpointBen 因为它不是实现细节 - 在全局常量None
下只有一个 None
对象。如果有的话,NoneType
是一个实现细节,因为None
单例必须具有 some 类型。 (您不能创建这种类型的实例这一事实很好地表明它的一个实例旨在成为单例。)
@BallpointBen 我认为关键在于 Python 拥有强大的对象标识概念。如果您想检查一个对象是否与None
比较等于,请务必使用obj == None
。如果要检查对象是否是 None
,请使用obj is None
。 PEP 8 建议(以及这个答案)的要点是,大多数人在想要检查 None 时都想要后者,而且它也恰好更快更清晰。
None
也不同于 0
和其他小整数等缓存对象,其中缓存实际上是一个实现细节。不同之处在于整数具有内在价值,它赋予了它的属性并且可以计算。另一方面,None
没有任何状态,只有它的 身份 才重要并使其与众不同。【参考方案3】:
PEP 8 定义在比较单例时最好使用is
运算符。
【讨论】:
【参考方案4】:我最近遇到了可能出错的地方。
import numpy as np
nparray = np.arange(4)
# Works
def foo_is(x=None):
if x is not None:
print(x[1])
foo_is()
foo_is(nparray)
# Code below raises
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
def foo_eq(x=None):
if x != None:
print(x[1])
foo_eq()
foo_eq(nparray)
我创建了一个函数,它可以选择将一个 numpy 数组作为参数,如果包含它,它会进行更改。如果我使用不等式运算符 !=
测试它是否包含,则会引发 ValueError(参见上面的代码)。如果我使用is not none
,代码可以正常工作。
【讨论】:
【参考方案5】:“==”与“is”不同的另一个实例。当您从数据库中提取信息并检查值是否存在时,结果将是值或无。
看看下面的 if 和 else。当数据库返回“无”时,只有“是”有效。如果你用 == 代替,if 语句将不起作用,它会直接转到 else,即使结果是“无”。希望我能说清楚。
conn = sqlite3.connect('test.db')
c = conn.cursor()
row = itemID_box.get()
# pull data to be logged so that the deletion is recorded
query = "SELECT itemID, item, description FROM items WHERE itemID LIKE '%" + row + "%'"
c.execute(query)
result = c.fetchone()
if result is None:
# log the deletion in the app.log file
logging = logger('Error')
logging.info(f'The deletion of row failed.')
messagebox.showwarning("Warning", "The record number is invalid")
else:
# execute the deletion
c.execute("DELETE from items WHERE itemID = " + row)
itemID_box.delete(0, tk.END)
messagebox.showinfo("Warning", "The record has been deleted")
conn.commit()
conn.close()
【讨论】:
【参考方案6】:我们可以以打印功能为例。看这里:
print(print())
print(None)
两者都输出无:
None
None
is
指的是实际的东西,无论它们是对象none。打印不是对象none。
print(None is print)
print(None is None)
现在我们得到了想要的结果。
False
True
PEP 8 也提到了这一点,说“与像 None 这样的单例的比较应该总是用 is 或 not 来完成,而不是相等运算符。”
is
也更快。
【讨论】:
我认为 PEP8 的引用是正确的答案,也许值得一提。我不明白你的例子的重点。 提问者说'如果是,为什么',所以这就是为什么,以避免错误。 PEP8 是一个附带的东西和一个格式指南。不过我还是放了,大家可以参考一下。 但是您的示例不正确。表达式print( None is print())
显示True
(在我的Python 3.8.6 副本上)。我会说“如果是,为什么”这个问题的答案只是 PEP8 推荐了这个成语,而提问者的编辑强制执行了这个建议。
哦,是的,对不起。应该是None is print
。我会马上解决的。以上是关于Python无比较:我应该使用“is”还是==?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 C# 'is' 运算符在比较两个布尔值时会给出正确的结果,我应该使用它吗?