Python中 in 操作符在集合与列表中的不同行为详解

python中 in 操作符在集合与列表中的不同行为详解

本文深入探讨了 Python 中 in 操作符在集合 (set) 和列表 (list) 这两种数据结构中的不同行为。通过分析其内部实现机制,解释了为何在某些情况下,使用 in 操作符时,列表会引发错误,而集合却能正常运行。同时,结合 PyTorch 张量 (Tensor) 的特性,提供了针对特定问题的解决方案,并给出了 in 操作符使用的注意事项。

in 操作符的工作原理

x in collection 在 Python 中的行为取决于 collection 的类型。具体来说,使用内部哈希表的集合和字典与不使用哈希表的列表和元组的工作方式不同。

列表和元组 (不使用哈希表)

当 collection 是列表或元组时,x in collection 的内部实现类似于以下伪代码:

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

此方法按顺序将 collection 中的每个元素 c 与 x 进行比较,直到找到第一个匹配项。首先比较身份 (is),如果身份不同,则比较相等性 (==)。

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

集合和字典 (使用哈希表)

当 collection 是集合或字典时,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

此方法首先从 collection 中选择哈希值与 x 匹配的元素子集。然后,它迭代该子集,并将每个元素 c 与 x 进行比较(首先比较身份,然后比较相等性),并在找到第一个匹配项时停止。哈希表的运用使得查找速度更快,尤其是在处理大型数据集时。

注意: 集合中元素的哈希值在元素添加到集合时计算,而 x 的哈希值在使用 in 操作符时计算。

示例:自定义类 MyObj

为了更清楚地理解 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={other}")        return self._val == other._val if isinstance(other, MyObj) else False    def __repr__(self):        return f""

创建 MyObj 类的实例,并将其添加到集合和列表中:

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__ 方法进行比较。

in 操作符与集合

>>> s{, , }>>> b in s calling __hash__True>>> d in s calling __hash__ calling __eq__, other= calling __eq__, other=True

使用 in 操作符时,Python 首先计算 x 的哈希值。如果存在哈希冲突,则还需要调用 __eq__ 方法。

in 操作符与列表

>>> lst[, , ]>>> a in lstTrue>>> b in lst calling __eq__, other= calling __eq__, other=True>>> d in lst calling __eq__, other= calling __eq__, other= calling __eq__, other= calling __eq__, other=True

对于列表,Python 首先检查身份 (x is c)。如果身份相同,则不需要检查相等性 (x == c)。如果身份不同,则检查相等性。

PyTorch 张量的特殊情况

PyTorch 张量在进行相等性比较时,如果形状不一致,会引发 RuntimeError。这是导致原始问题中列表引发错误的原因。

import torcha = torch.Tensor(2,3)b = torch.Tensor(2)# case 1a:# b  in list([a,a,b]) # raises an error: # RuntimeError: The size of tensor a (2) must match the size of tensor b (3) at non-singleton dimension 0# case 1bb in set([a,a,b]) # True (i.e. no error)

在 b in list([a, b]) 中,由于 a 和 b 的形状不同,在进行 b == a 比较时会引发 RuntimeError。而在 b in set([a, b]) 中,由于集合首先进行哈希值比较,而 torch.Tensor 的哈希值是其内存地址,因此在绝大多数情况下 hash(a) 和 hash(b) 是不同的,从而避免了 b == a 的比较,避免了错误。

解决方案

一种解决方案是使用 torch.Tensor.size() 属性(它是元组的子类),并创建一个字典或集合,用于存储不同大小的张量。

import torchtensors_by_size = {}a = torch.Tensor(2, 3)b = torch.Tensor(2)size_a = tuple(a.size())size_b = tuple(b.size())if size_a not in tensors_by_size:    tensors_by_size[size_a] = set()tensors_by_size[size_a].add(a)if size_b not in tensors_by_size:    tensors_by_size[size_b] = set()tensors_by_size[size_b].add(b)# Now you can check if a tensor of a certain size existstarget_tensor = torch.Tensor(2)target_size = tuple(target_tensor.size())if target_size in tensors_by_size:    print("Tensor of size", target_size, "exists.")    if target_tensor in tensors_by_size[target_size]:        print("Tensor exists in the collection")    else:        print("Tensor of that size exists, but not that specific tensor.")else:    print("Tensor of size", target_size, "does not exist.")

总结

in 操作符在 Python 中对于集合和列表的行为有所不同。理解其内部实现机制,可以帮助我们更好地利用这些数据结构,并避免潜在的错误。在处理 PyTorch 张量等特殊类型时,需要特别注意其相等性比较的规则,并采取相应的解决方案。使用哈希表可以优化查找速度,但在某些情况下,可能会掩盖潜在的错误。因此,在选择数据结构时,需要根据实际情况进行权衡。

以上就是Python中 in 操作符在集合与列表中的不同行为详解的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1373699.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 13:29:36
下一篇 2025年12月14日 13:29:50

相关推荐

  • python怎么进行日志记录_python日志记录logging模块使用指南

    Python的内置logging模块通过日志级别、多处理器支持、灵活格式化和集中管理等特性,提供比print更强大、可配置的日志解决方案,适用于开发与生产环境。 Python中进行日志记录,核心就是使用其内置的logging模块。它提供了一个灵活且强大的框架,远比简单的print语句在处理程序运行时…

    好文分享 2025年12月14日
    000
  • 满足线性约束条件的随机向量生成教程

    本文将介绍一种高效生成满足特定线性约束条件的随机向量的方法。 传统的随机生成并验证的方法在需要大量样本时效率低下。 本文将介绍如何利用线性规划优化方法,通过求解线性规划问题来直接获得满足约束条件的随机向量,从而显著提高生成效率。 通过示例代码和详细解释,帮助读者理解和应用该方法。 在许多科学计算和工…

    2025年12月14日
    000
  • 解决 pip install 错误:调整 Python 环境路径

    本文旨在解决使用 pip install 命令时遇到的“Fatal error in launcher”错误,该错误通常是由于系统环境中的 Python 或 pip 路径配置不正确所致。我们将详细指导如何通过修改系统环境变量 Path 来修正错误的路径指向,确保 pip 能够正确调用所需版本的 Py…

    2025年12月14日
    000
  • 如何利用字典为Pandas DataFrame添加基于子字符串匹配的分类列

    本文详细介绍了如何使用Python的Pandas库,结合字典对DataFrame中的文本列进行分类。当字典的键是DataFrame列中字符串的子集时,传统的map方法无法直接应用。本教程通过apply方法与自定义的lambda函数,演示了如何高效地识别并分配类别,确保即使面对部分匹配的复杂情况也能准…

    2025年12月14日
    000
  • 深入理解 Python 类型变量与联合类型:避免 Pyright 报错的策略

    本文探讨了 Python 中 TypeVar 与联合类型(Union Type)结合使用时常见的类型检查问题,特别是当 TypeVar 被约束为特定类型时,如何正确处理 float | np.ndarray 或 float | Fraction 等联合类型输入。文章详细解释了 Pyright 等工具…

    2025年12月14日
    000
  • 使用Python函数高效生成斐波那契数列

    本文将详细介绍如何使用Python函数生成斐波那契数列。我们将从函数定义、初始化序列和循环逻辑等方面逐步构建解决方案,并提供清晰的代码示例。特别强调初学者常犯的错误——定义函数后忘记调用,以确保读者能够顺利实现并获取预期的斐波那契数列输出。通过本文,您将掌握使用Python函数生成斐波那契数列的核心…

    2025年12月14日
    000
  • Python自动化粘贴文本:加速消息发送的策略与挑战

    本文探讨在Python中实现自动化文本粘贴以提高消息发送效率的方法。针对pyautogui.typewrite速度慢的问题,我们首先尝试结合clipboard模块和pyautogui.hotkey进行粘贴操作,并分析其可能遇到的问题。接着,介绍一种基于屏幕元素识别和鼠标模拟的临时性替代方案,但强调其…

    2025年12月14日
    000
  • Python ctypes结构体深度复制技巧:解决指针字段问题

    本教程详细介绍了如何在Python中使用ctypes库对包含指针字段的结构体进行深度复制。通过结合from_buffer_copy进行浅层复制,并手动迭代和复制指针指向的外部数据,我们能够确保生成一个完全独立的新结构体实例,避免原始数据修改对副本造成影响。 引言 Python的ctypes库为Pyt…

    2025年12月14日
    000
  • 深入理解 Python ctypes 结构体及其指针的深度复制

    在 Python ctypes 模块中,对包含指针的结构体进行深度复制是一项复杂任务。本文将详细介绍如何正确地复制 ctypes 结构体,特别是当结构体成员包含指向外部动态分配数据的指针时。我们将探讨 from_buffer_copy 方法进行浅层复制,并结合手动迭代和 ct.cast 来实现指针所…

    2025年12月14日
    000
  • Python ctypes结构体深度复制指南

    在Python中使用ctypes处理C风格结构体时,若结构体包含指向动态分配数据的指针字段,常规的浅拷贝或copy.deepcopy无法正确复制指针所指向的数据。本教程将详细介绍如何为ctypes.Structure实现一个自定义的深度复制方法,通过from_buffer_copy进行浅拷贝,并针对…

    2025年12月14日
    000
  • Python十六进制地址到字节序列的转换与字节字面量解析

    本文旨在解决将十六进制地址(如0x7ffd6fa90940)转换为其对应的字节序列表示(如b’x40x09xa9x6fxfdx7fx00x00’)时遇到的常见问题,特别是关于Python字节字面量的显示差异和大小端(endianness)的理解。文章将深入探讨struct.p…

    2025年12月14日
    000
  • Python 数据分箱:处理混合类型与自定义分类的完整指南

    本文详细介绍了在Python Pandas中如何将混合数据类型(包含数值和文本)的年龄数据有效地划分到预定义的分类区间。通过解决pd.cut函数中常见的“分箱标签数量与分箱边界不匹配”错误,并结合pd.to_numeric和fillna等方法,实现对非数值和缺失值统一归类为“unknown”,最终生…

    2025年12月14日
    000
  • Python ctypes结构体深度复制:处理指针字段的完整指南

    本文深入探讨了在Python中使用ctypes库时,如何对包含指针字段的Structure进行深度复制。由于ctypes结构体模拟C语言内存布局,其指针字段仅存储内存地址。实现深度复制的关键在于,首先对结构体本身进行浅复制,然后遍历所有指针字段,为它们指向的外部数据创建全新的副本,并更新复制结构体中…

    2025年12月14日
    000
  • Python Pandas数据分箱:处理年龄分类与非数值数据

    本文详细介绍了如何使用Pandas对年龄数据进行分箱处理,包括将数值归类到预定义的年龄区间、处理非数值和缺失值并将其归为“未知”类别,以及确保分类标签的正确性和顺序。通过pd.cut和pd.to_numeric的组合应用,有效解决数据清洗和分类中的常见问题,提供清晰、可复用的数据处理方案。 1. 引…

    2025年12月14日
    000
  • Heroku 上 Flask API 与 Dash 应用的部署与集成

    本文探讨了在 Heroku 部署 Flask API 与 Dash 应用时常见的 405 Method Not Allowed 错误及其解决方案。核心问题在于 Heroku 的 Procfile 配置与 Flask 和 Dash 应用实例的交互方式。通过将 Dash 应用集成到主 Flask 实例中…

    2025年12月14日
    000
  • Python数值计算陷阱:正确处理用户输入的成绩数据

    本文深入探讨Python中用户输入数据导致数值计算错误的常见陷阱。当用户输入数字时,Python默认将其视为字符串,若直接进行算术运算,可能发生字符串连接而非数值相加。本教程将详细解析此问题,并提供两种将字符串输入正确转换为整数的有效方法,确保数据处理的准确性与程序的健壮性。 在python编程中,…

    2025年12月14日
    000
  • HDF5 大数据存储优化:高效分块策略与实践

    处理大型科学数据集时,HDF5 是一种常用的存储方案,但其写入性能往往成为瓶颈。本文旨在探讨如何通过优化 HDF5 的分块(chunking)策略来显著提升大数据集的写入效率。我们将深入分析不当分块导致性能低下的原因,并提供一个与数据访问模式高度匹配的优化方案,辅以 Python 示例代码,帮助读者…

    2025年12月14日
    000
  • Django中实现可选ForeignKey字段的表单验证指南

    本文详细探讨了在Django应用中,即使模型层已将ForeignKey字段设置为可选(blank=True, null=True),在自定义表单中仍可能被强制要求填写的问题。核心解决方案是在自定义的forms.ModelChoiceField中明确设置required=False,以确保表单验证与模…

    2025年12月14日
    000
  • SQLAlchemy动态WHERE子句构建指南

    本文旨在指导读者如何在SQLAlchemy中构建动态的WHERE子句,以适应不同客户端输入和多变的查询需求。通过将过滤条件抽象为可迭代的表达式列表,并利用辅助函数进行应用,我们能够灵活地组合查询条件,从而实现高度可配置的数据检索功能,有效应对简单键值对或复杂逻辑组合的动态过滤场景。 1. 引言:动态…

    2025年12月14日
    000
  • SQLAlchemy动态查询:灵活构建WHERE条件

    本文旨在探讨如何在SQLAlchemy中实现动态的WHERE子句,以应对客户端输入或业务逻辑变化带来的查询条件不确定性。我们将介绍一种核心策略:将查询条件预定义为独立的表达式列表,并通过迭代方式将其应用到SELECT语句中,从而实现高度灵活且可扩展的查询构建。此外,文章还将涵盖如何将字典形式的动态输…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信