Python中,对象相等性比较相关关键字包括is、in,比较运算符有==。
is判断两个对象的标识号是否相等
in用于成员检测
==用于判断值或内容是否相等,默认是基于两个对象的标识号比较
也就是说,如果a is b为True且如果按照默认行为,意味着a==b也为True。
is判断标识号是否相等
is比较的是两个对象的标识号是相等,Python中使用id()函数获取对象的标识号。
1 2 3 4 5 6
| >>> a = [ 1, 2, 3] >>> id(a) 4355817792 >>> b = [ 1, 2, 3] >>> id(b) 4355822976
|
上面创建的两个列表实例位于不同的内存地址,所以它们的标识号不等。
即便对于两个空列表实例,它们is比较的结果也是False:
1 2 3
| >>> a, b = [], [] >>> a is b False
|
数据类型不同
序列型、字典型、集合型
对于序列型、字典型、集合型对象,一个对象实例指向另一个对象实例,is比较才返回真值。
1 2 3 4
| >>> a, b = { 'a':[1,2,3]},{'id':'book id', 'price':'book price'} >>> a = b >>> a is b True
|
值类型
对于值类型而言,不同的编译器可能会做不同的优化。从性能角度考虑,它们会缓存一些值类型的对象实例。所以,使用is比较时,返回的结果看起来会有些不太符合预期。以下有两种情况,同样的整数值,使用is得到不同结果
情况一
1 2 3 4
| >>> a = 123 >>> b = 123 >>> a is b True
|
情况二
1 2 3 4
| >>> c = 123456 >>> d = 123456 >>> c is d False
|
Python解释器,对位于[-5, 256]内的小整数,会进行缓存,不在该范围内的不会缓存,所以会出现以上的情况。
None
Python中None对象是一个单例类的实例,具有唯一的标识号,如下所示:
在判断某个对象是否为None时,最便捷的做法:variable is None,如下所示:
1 2 3 4 5
| >>> a = None >>> a is None True >>> id(a) 4359531472
|
in用于成员检测
- 如果元素i是s的成员,则
i in s为True
- 若不是s的成员,则返回False,也就是
i not in s为True
对于字符串类型,i in s为True,意味着i是s的子串,也就是s.find(i)返回大于-1的值。
1 2 3 4 5 6 7 8
| >>> 'ab' in 'abc' True >>> 'abc'.find('ab') 0 >>> 'ab' in 'acb' False >>> 'abc'.find('ac') -1
|
内置的序列类型、字典类型和集合类型
内置的序列类型、字典类型和集合类型,都支持in操作。对于字典类型,in操作判断i是否是字典的键值。
1 2 3 4
| >>> [1, 2] in [[1, 2], 'str'] True >>> 'apple' in { 'orange':1.5, 'banana':2.3, 'apple':5.2 } True
|
自定义类型
对于自定义类型,判断是否位于序列类型中,需要重写序列类型的魔法方法__contains__
具体操作步骤如下:
- 自定义Student类
- Students类继承list,并重写
__contains__方法
根据Student类的name属性,判断某Student是否在Students序列对象中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Student(): def __init__(self, name): self._name = name
@property def name(self): return self._name
@name.setter def name(self, val): self._name = val
class Students(list): def __contains__(self, stu): for s in self: if s.name == stu.name: return True return False
|
Student、Students类的示意图:

1 2 3 4 5 6 7 8 9 10
| s1 = Student('xiaoming') s2 = Student('xiaohong')
a = Students() a.extend([s1, s2])
s3 = Student('xiaoming') print(s3 in a) s4 = Student('xiali') print(s4 in a)
|
使用自定义类,s3的名字与列表a中的第一个元素s1重名,所以s3 in a返回True。
s4不在列表a中,所以in返回False。
==判断值是否相等
数值型、字符串、列表、字典、集合
对于数值型、字符串、列表、字典、集合,默认只要元素值相等,==比较结果是True。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| >>> str1 = "alg-channel" >>> str2 = "alg-channel" >>> str1 == str2 True >>> a = [ 1, 2, 3 ] >>> b = [ 1, 2, 3 ] >>> a == b True >>> c = [ 1, 3, 2 ] >>> a == c False >>> a = { 'a': 1.0, 'b': 2.0 } >>> b = { 'a': 1.0, 'b': 2.0 } >>> a == b True >>> c = ( 1, 2 ) >>> d = ( 1, 2 ) >>> c == d True >>> c = { 1, 2, 3 } >>> d = { 1, 3, 2 } >>> c == d True
|
自定义类型
对于自定义类型,当所有属性取值完全相同的两个实例,判断==时,返回False。
但是,大部分场景下,我们希望这两个对象是相等的,这样不用重复添加到列表中。如:判断用户是都已经登入时,只要用户所有属性与登入列表中某个用户完全一致时,就认为已经登入。
如下实例,自定义类型重写方法__eq__,使用__dict__获取实例的所有属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Student(): def __init__(self, name, age): self._name = name self._age = age
@property def name(self): return self._name
@name.setter def name(self, val): self._name = val
@property def age(self): return self._age
@age.setter def age(self, val): self._age = val
def __eq__(self, val): print(self.__dict__) return self.__dict__ == val.__dict__
|
Student类的示意图

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| a = [] xiaoming = Student('xiaoming', 29) if xiaoming not in a: a.append(xiaoming)
xiaohong = Student('xiaohong', 30) if xiaohong not in a: a.append(xiaohong)
xiaoming2 = Student('xiaoming', 29) if xiaoming2 == xiaoming: print('对象完全一致,相等')
if xiaoming2 not in a: a.append(xiaoming2)
print(len(a))
|
执行结果
1 2 3 4 5 6 7 8
| /Users/lvjing/PycharmProjects/python_base_project/venv/bin/python /Users/lvjing/PycharmProjects/python_base_project/object_sample_02.py {'_name': 'xiaoming', '_age': 29} {'_name': 'xiaoming', '_age': 29} 对象完全一致,相等 {'_name': 'xiaoming', '_age': 29} 2
Process finished with exit code 0
|
第三个实例 xiaoming2 与已添加到列表 a 中的 xiaoming 属性完全一致,所以 == 比较或 in 时,都会返回 True。
