🐍Python 语言基础
is与==
面试回答
常见问法
is 和 == 的区别是什么?
回答
is 比较的是两个引用是否指向同一个对象,也就是对象身份;== 比较的是对象值是否相等。面试里最重要的是讲清”身份”和”值”这两个维度不同。
# 基本区别示例
a = [1, 2, 3]
b = [1, 2, 3]
print(f"值相等: {a == b}") # True,值相同
print(f"身份相同: {a is b}") # False,不同对象
# 身份比较的应用场景
x = None
print(f"x是None: {x is None}") # True,推荐用is比较None
# 小整数缓存示例(Python实现细节)
c = 256
d = 256
print(f"小整数c==d: {c == d}") # True
print(f"小整数c is d: {c is d}") # True(小整数缓存优化)
# 大整数示例
e = 257
f = 257
print(f"大整数e==f: {e == f}") # True
print(f"大整数e is f: {e is f}") # False(不同对象)
# 字符串驻留示例(Python实现细节)
g = "hello"
h = "hello"
print(f"字符串g==h: {g == h}") # True
print(f"字符串g is h: {g is h}") # True(字符串驻留优化)
# 自定义类示例
class Person:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return isinstance(other, Person) and self.name == other.name
p1 = Person("Alice")
p2 = Person("Alice")
p3 = p1
print(f"p1 == p2: {p1 == p2}") # True,__eq__比较name
print(f"p1 is p2: {p1 is p2}") # False,不同对象
print(f"p1 is p3: {p1 is p3}") # True,同一个对象
追问
- 为什么有时小整数或短字符串看起来
is也成立?(解释器优化) - 自定义类里
==的行为由谁决定?(__eq__方法) - 为什么比较
None时通常推荐用is?(单例模式)
原理展开
is 本质上是对象身份比较,通常等价于”是不是同一个对象”。== 则会走对象的相等性逻辑,例如调用 __eq__。因此两个不同对象完全可能 == 为真,但 is 为假。
一些解释器优化会让小整数或驻留字符串复用对象,但这属于实现层优化,不应该把它当作逻辑判断依据。
# 对象身份的本质
def print_identity(obj):
print(f"对象id: {id(obj)}")
return id(obj)
# 身份比较的底层实现
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(f"a的id: {id(a)}")
print(f"b的id: {id(b)}") # 与a相同
print(f"c的id: {id(c)}") # 与a不同
print(f"a is b: {a is b}") # True,id相同
print(f"a is c: {a is c}") # False,id不同
# __eq__ vs is 的实现差异
class CustomObject:
def __init__(self, value):
self.value = value
def __eq__(self, other):
print(f"调用__eq__比较 {self.value} 和 {other.value}")
return isinstance(other, CustomObject) and self.value == other.value
obj1 = CustomObject(42)
obj2 = CustomObject(42)
# 使用is(不调用__eq__)
result_is = obj1 is obj2
print(f"obj1 is obj2: {result_is}")
# 使用==(调用__eq__)
result_eq = obj1 == obj2
print(f"obj1 == obj2: {result_eq}")
# 身份比较的典型应用场景
# 1. 比较单例对象
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
s1 = Singleton()
s2 = Singleton()
print(f"单例s1 is s2: {s1 is s2}") # True,同一个实例
# 2. 比较None(推荐用法)
def check_none(x):
if x is None: # 推荐用is,不是x == None
return "是None"
return "不是None"
# 3. 比较布尔值
def check_boolean(x):
if x is True: # 明确检查True,不是truthy值
return "是True"
elif x is False:
return "是False"
return "不是布尔值"
# 4. 快速比较
def fast_comparison(a, b):
# 先比较身份(快速),再比较值
if a is b:
return True
return a == b
易错点
- 用
is比较普通值相等(如if x is 42) - 把解释器优化现象当成语言保证
- 在需要值相等的地方用
is,在需要身份比较的地方用== - 混淆
is和in的使用场景
记忆技巧
记住 is 和 == 的区别口诀:
- is = “是不是同一个对象”(身份比较)
- == = “值是不是相等”(值比较)
典型使用场景:
- 用 is:比较 None、比较单例、比较布尔值、快速身份检查
- 用 ==:比较数值、比较字符串内容、比较容器内容、自定义对象相等性
Python实现细节(不应依赖):
- 小整数缓存(-5到256)
- 字符串驻留(短字符串)
- 这些是优化行为,不是语言规范