编程Python 库开发者

在 Python 中,__getitem__ 方法是如何工作的,为什么要实现它,以及在处理切片时需要考虑什么?

用 Hintsage AI 助手通过面试

答案。

问题背景

getitem 方法被添加到 Python 中,作为序列和映射协议的一部分。通过这个魔术方法,标准集合(如列表、元组、字典等)支持通过索引、键和切片访问。在用户定义的类中,该方法允许对象表现得像“集合”。

问题

没有实现 getitem 的用户定义类不支持索引和 for 循环迭代。如果只为简单的索引实现该方法,则在希望完整支持切片时是不适用的,而忽略不同类型的索引会导致错误。

解决方案

实现 getitem 来支持索引和切片对象,并将其处理分开。这允许在标准 Python 结构中使用用户定义的对象(例如,支持切片 your_obj[1:5])。

代码示例:

class MyRange: def __init__(self, n): self.n = n def __getitem__(self, item): if isinstance(item, int): # 单个索引 if 0 <= item < self.n: return item * 2 raise IndexError('索引超出范围') elif isinstance(item, slice): # 切片 return [self[i] for i in range(*item.indices(self.n))] else: raise TypeError('无效的参数类型:{}'.format(type(item))) mr = MyRange(10) print(mr[3]) # 6 print(mr[2:5]) # [4, 6, 8]

关键特点:

  • getitem 是序列和可迭代性协议的基础
  • 为了支持切片,需要单独处理 slice
  • IndexError 和 TypeError 异常是标准函数(例如,list(),for)正常工作所需的

具有陷阱的问题。

仅实现 getitem 是否可以通过索引赋值?

不可以。为了支持赋值(your_obj[i] = value),需要实现 setitemgetitem 仅负责读取。

getitem 是否必须像列表那样在切片上返回列表?

不可以。主要是返回“序列”,考虑到类的含义(可以返回相同类型或例如,元组)。最重要的是,这在上下文中是有意义的。

为什么有时会出现 TypeError 错误:'MyClass' 对象不可下标?

如果您尝试执行 my_obj[0],而类没有实现 getitem,就会出现该消息。为了使类可下标(支持 []),该方法是必须的。

常见错误和反模式

  • 仅检查 int,忽略 slice:切片总是会出现错误
  • 返回错误类型(例如,在切片时返回 None 而不是序列)
  • 不抛出 IndexError,导致 for 循环行为不正确

生活中的例子

消极案例

只为 int 实现了 getitem,忘记了切片。任何尝试 my_obj[2:5] 的行为都会导致 TypeError 并导致整个集合处理算法失败。

优点:

  • 简单

缺点:

  • 不支持切片,代码与大多数标准结构不兼容

积极案例

getitem 已经实现了单独处理 slice 和 int。切片和索引有效,list()、map() 和迭代方法在没有额外努力的情况下得到支持。

优点:

  • 类与 Python 的标准工具兼容
  • 易于扩展以支持任何索引类型(元组、字符串用于矩阵等)

缺点:

  • 实现需要稍微多一些代码和测试