Python具有某些类型,可以保证只有一个实例。这些实例的例子是None
,NotImplemented
和Ellipsis
。这些是(按定义)单身人士,因此之类的事情None is None
一定会返回,True
因为无法创建的新实例nonetype
。
它还提供了几个doubletons 1 True
,False
2 -所有引用True
指向同一个对象。同样,这是因为无法创建的新实例bool
。
python语言保证了以上所有内容。但是,您已经注意到,有些类型(全部不可变)存储一些实例以供重用。这是语言所允许的,但是不同的实现可以选择是否使用此配额- 取决于其优化策略。属于此类的一些示例是小整数(-5-> 255),emptytuple
和empty frozenset
。
最后,cpythonintern
在解析过程中某些不变的对象…
例如,如果您使用cpython运行以下脚本,则会看到它返回True
:
def foo():
return (2,)
if __name__ == '__main__':
print foo() is foo()
这似乎 很 奇怪。cpython正在玩的技巧是,每当构造函数时foo
,它都会看到包含其他简单(不可变)文字的元组字面量。python不会一遍又一遍地创建此元组(或其等效项),而只是创建一次。由于整个交易是不可变的,因此没有更改该对象的危险。反复调用相同的紧密循环对于性能而言可能是一个巨大的胜利。小绳子也会被扣留。真正的胜利在于字典查找。Python可以做一个(非常快的)指针比较,然后在检查哈希冲突时退回到较慢的字符串比较上。由于大量的python建立在字典查找上,因此对于整个语言来说,这可能是一个很大的优化。
1我可能只是编造了这个词…但希望您能理解… 2在正常情况下,您 不需要 检查对象是否是对它的引用- 通常,您只关心对象是否为“真”-例如,如果将执行分支。但是,我将其放在此处只是为了完整性。 __True``if some_instance: ...
请注意,is
可以用来比较不是单例的事物。一种常见用法是创建一个哨兵值:
sentinel = object()
item = next(iterable, sentinel)
if items is sentinel:
# iterable exhausted.
要么:
_sentinel = object()
def function(a, b, none_is_ok_value_here=_sentinel):
if none_is_ok_value_here is sentinel:
# Treat the function as if `none_is_ok_value_here` was not provided.
如果要检查一个值 是否是 另一个值,请使用is
运算符。如果要检查一个值 是否等于 另一个值(但可能不同),请使用==
。有关is
和之间==
(以及何时使用哪种)的区别的更多详细信息,请参阅以下文章之一:
我们讨论了这些cpython实现细节,并声称它们是优化。最好只是衡量我们从所有优化中得到的收益(与is
操作员一起工作时会产生一些混乱)。