🐍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,在需要身份比较的地方用 ==
  • 混淆 isin 的使用场景

记忆技巧

记住 is== 的区别口诀:

  1. is = “是不是同一个对象”(身份比较)
  2. == = “值是不是相等”(值比较)

典型使用场景:

  • 用 is:比较 None、比较单例、比较布尔值、快速身份检查
  • 用 ==:比较数值、比较字符串内容、比较容器内容、自定义对象相等性

Python实现细节(不应依赖):

  • 小整数缓存(-5到256)
  • 字符串驻留(短字符串)
  • 这些是优化行为,不是语言规范