讲师中心 微信公众号
AI工具推荐 视频效率加速

Python 中 in 运算符在集合和列表中的不同行为解析

轻磊小哥_6281

轻磊小哥_6281

发布时间:2025-09-25 16:52:26

|

464人浏览过

|

来源于php中文网

原创

python 中 in 运算符在集合和列表中的不同行为解析

Python 中 in 运算符在集合和列表中的不同行为解析

本文深入探讨了 Python 中 in 运算符在不同数据结构(尤其是列表和集合)中的行为差异。通过分析内部实现机制,解释了为何在特定场景下,使用列表会引发错误,而使用集合却能正常运行。同时,结合 PyTorch 张量的特性,提供了针对性解决方案和代码示例,帮助读者更好地理解和应用 in 运算符。

在 Python 中,in 运算符用于检查某个元素是否存在于一个集合(collection)中。然而,对于不同类型的集合,其内部实现机制存在差异,导致在某些情况下会产生不同的结果。本文将深入探讨 in 运算符在列表(list)和集合(set)中的行为差异,并结合具体的 PyTorch 张量示例,解释其背后的原因,并提供相应的解决方案。

in 运算符的工作原理

x in collection 的具体行为取决于 collection 的类型。通常,使用内部哈希表的数据结构(如集合和字典)与不使用哈希表的数据结构(如列表和元组)的处理方式不同。

不使用哈希表的集合(列表、元组等)

对于列表和元组等不使用哈希表的集合,x in collection 的内部实现逻辑如下(伪代码):

立即学习“Python免费学习笔记(深入)”;

def is_in(x, collection):
  for c in collection:
      if (x is c or x==c):
          return True
  return False

该过程会遍历集合中的每个元素 c,依次进行身份比较 (x is c) 和相等性比较 (x == c),直到找到第一个匹配项。

使用哈希表的集合(集合、字典等)

对于集合和字典等使用哈希表的集合,x in collection 的内部实现逻辑如下(伪代码):

def is_in(x, collection):
  # 选择集合中哈希值与 x 相同的元素子集
  subset = get_subset_by_hash(collection, hash(x))
  for c in subset:
      if (x is c or x==c):
          return True
  return False

该过程首先根据 x 的哈希值,从集合中筛选出哈希值相同的元素子集 subset。然后,遍历 subset 中的每个元素 c,依次进行身份比较和相等性比较,直到找到第一个匹配项。哈希表的应用显著提高了查找效率,尤其是在大型数据集中。

实例分析

为了更深入地理解 in 运算符的行为,我们创建一个自定义类 MyObj,并定义其哈希计算逻辑 (__hash__) 和相等性判断逻辑 (__eq__):

class MyObj:
    def __init__(self, val, hashval):
        self._val = val
        self._hashval = hashval

    def __hash__(self):
        print(f"{str(self)} calling __hash__")
        return self._hashval

    def __eq__(self, other):
        print(f"{str(self)} calling __eq__, {other=}")
        return super().__eq__(other)

    def __repr__(self):
        return f"<{self.__class__.__name__}: {self._val}>"

接下来,创建 MyObj 的几个实例,并分别构建一个集合 s 和一个列表 lst:

a = MyObj("a", 123)
b = MyObj("b", 456)
d = MyObj("d", 456)  # 与 b 具有相同的哈希值

print("Creating set `s`")
s = set([a, b, d])

print("Creating list `lst`")
lst = [a, b, d]

在创建集合时,Python 会计算每个元素的哈希值。如果存在哈希冲突(例如,b 和 d 具有相同的哈希值),则会调用 __eq__ 方法进行相等性判断。

python 查询技能
python 查询技能

查询客流数据,输出JSON格式,可直接导入Bitable等可视化工具

下载

在集合中使用 in 运算符

>>> s
{<MyObj: a>, <MyObj: b>, <MyObj: d>}
>>> b in s
<MyObj: b> calling __hash__
True
>>> d in s
<MyObj: d> calling __hash__
<MyObj: b> calling __eq__, other=<MyObj: d>
<MyObj: d> calling __eq__, other=<MyObj: b>
True

在集合中使用 in 运算符时,Python 首先计算 x 的哈希值。如果存在哈希冲突,则会调用 __eq__ 方法进行相等性判断。

在列表中使用 in 运算符

>>> lst
[<MyObj: a>, <MyObj: b>, <MyObj: d>]
>>> a in lst
True
>>> b in lst
<MyObj: a> calling __eq__, other=<MyObj: b>
<MyObj: b> calling __eq__, other=<MyObj: a>
True
>>> d in lst
<MyObj: a> calling __eq__, other=<MyObj: d>
<MyObj: d> calling __eq__, other=<MyObj: a>
<MyObj: b> calling __eq__, other=<MyObj: d>
<MyObj: d> calling __eq__, other=<MyObj: b>
True

在列表中使用 in 运算符时,Python 会依次遍历列表中的每个元素,首先进行身份比较 (x is c)。如果身份比较失败,则调用 __eq__ 方法进行相等性判断。

PyTorch 张量的特殊情况

在 PyTorch 中,如果尝试比较两个大小不同的张量,会引发 RuntimeError。PyTorch 张量的哈希值是通过 id(self) 计算的,即对象的内存地址。

import torch
a = torch.Tensor(2,3)
b = torch.Tensor(2)

# case 1a:
# b  in list([a,a,b]) # raises an error: 
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# RuntimeError: The size of tensor a (2) must match the size of tensor b (3) at non-singleton dimension 0

# case 1b
b in set([a,a,b]) # True (i.e. no error)

当执行 b in list([a, b]) 时,会依次进行以下比较:

  1. id(b) is id(a) -> False
  2. b == a -> 引发 RuntimeError

由于 b == a 引发了错误,因此永远不会将 b 与列表中的 b 进行比较。

当执行 b in set([a, a, b]) 时,由于集合使用哈希表,会首先比较哈希值。因为 Tensor.__hash__ 返回张量的 id,所以集合的哈希表类似于 {id(a): a, id(b): b}。b in s 的执行过程如下:

  1. hash(b) 是否与 s 的哈希表中的任何哈希值相同?是的,相同。
  2. b is b?(in 运算符左侧的 b 是否与集合中具有相同哈希值的对象相同?)是的,相同。

因此,不会引发 RuntimeError。

总结: 列表会按顺序检查 (x is c or x==c),而集合会首先检查哈希值,然后迭代集合中具有相同哈希值的所有项目,以检查 (x is c or x==c)。由于 hash(b) != hash(a),因此几乎永远不会比较 b == a,从而避免了 RuntimeError。

解决方案

为了解决这个问题,可以利用 torch.Tensor.size 属性(它是元组的子类),并创建一个字典,其中键是张量的大小,值是具有该大小的张量的集合(或列表)。

import torch

tensors = {}
a = torch.Tensor(2, 3)
b = torch.Tensor(2)
c = torch.Tensor(2, 3)

def add_tensor(tensor, tensors):
  size = tuple(tensor.size())
  if size not in tensors:
    tensors[size] = set()
  tensors[size].add(tensor)

add_tensor(a, tensors)
add_tensor(b, tensors)
add_tensor(c, tensors)

def check_tensor(tensor, tensors):
  size = tuple(tensor.size())
  return tensor in tensors.get(size, set())

print(check_tensor(b, tensors)) # Output: True
print(check_tensor(torch.Tensor(2), tensors)) # Output: False

结论

本文详细分析了 Python 中 in 运算符在列表和集合中的不同行为,并结合 PyTorch 张量的特殊情况,解释了引发 RuntimeError 的原因。通过理解其内部实现机制,可以更好地选择合适的数据结构,并避免潜在的错误。同时,本文提供了针对性的解决方案,帮助读者在实际应用中更好地处理类似问题。

热门AI工具

更多
PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6044

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2864

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

1752

2025.10.17

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6044

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2864

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

1752

2025.10.17

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2501

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

356

2025.12.22

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

0

2026.10.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn