Python魔法函数详解:__repr__、__str__与序列操作实现

Ruby
Ruby
发布时间:2026-10-13| 2人浏览过
原创

本文深入解析Python中常用的魔法函数,包括用于对象字符串表示的__repr__与__str__的区别,以及实现序列行为的__getitem__、__len__、__setitem__和__delitem__。通过具体代码示例,展示如何自定义类的行为以支持索引访问、长度查询和属性赋值,帮助开发者更好地理解Python的面向对象特性。

Python魔法函数概述

Python提供了一系列以双下划线开头和结尾的特殊方法,通常被称为魔法函数或魔术方法。这些方法允许开发者自定义类的行为,使其在特定操作下表现出预期的结果。

__repr__与对象字符串表示

__repr__

在Python中,__repr__函数对应内置的repr(object)函数,其目的是返回一个对象的“官方”字符串表示形式。这个字符串通常旨在准确反映对象的内部状态,便于调试和开发。如果直接打印一个未定义该方法的类实例,结果往往不够直观。


class A():
  def __init__(self,name=None,id=1):
    self.id=id
    self.name=name

if __name__ == '__main__':
  a=A()
  print(a)

输出结果


<__main__.A object at 0x0000018DF8E7EAC8>

默认情况下,直接打印类实例会返回对象的内存地址,格式如<__main__.ClassName object at 0x...>,这对用户来说并不友好。为了改善这一点,我们可以通过定义__repr__方法来自定义输出内容,再次运行代码观察变化。


class A():
  def __init__(self,name=None,id=1):
    self.id=id
    self.name=name
  def __repr__(self):
    return "进入函数"

if __name__ == '__main__':
  print(A())

输出结果


进入函数

__str__

__str__与__repr__的区别


class A():
  def __init__(self,name=None,id=1):
    self.id=id
    self.name=name
  def __str__(self):
    return "进入函数"

if __name__ == '__main__':
  print(A())

输出结果


进入函数

比较repr和str

虽然在使用print()函数时,__repr__和__str__的表现可能看起来相同,但二者有本质区别。__str__主要面向最终用户,旨在提供易读的、非正式的字符串表示;而__repr__面向开发者,旨在提供精确的、可用于重建对象的字符串表示。在交互式命令行中,直接输入变量名会调用__repr__,而__str__仅在明确调用str()或print()时生效。此外,如果未定义__str__,Python会回退使用__repr__。

__getitem__实现索引访问

__getitem__

如果在类中定义了__getitem__(self, key)方法,其实例对象A就可以通过A[key]的方式进行取值。当执行A[key]运算时,Python会自动调用类中的__getitem__方法,并将key作为参数传递进去。


class A():
  def __init__(self,name=None,id=1):
    self.id=id
    self.name=name
  def __repr__(self):
    return "进入函数"
  def __getitem__(self, item):
    return item
if __name__ == '__main__':
  a=A('lisa','123')
  print(a['name'])
  print(a[124])

输出


name
124

无论实例对象的key是否存在,调用A[key]时都会触发__getitem__方法,其返回值即为该方法中指定的return值。如果__getitem__实现不当,可能导致逻辑错误或异常。我们可以修改代码,调整__getitem__的返回值逻辑,以更好地处理属性访问。


class A():
  def __init__(self,name=None,id=1):
    self.id=id
    self.name=name
  def __repr__(self):
    return "进入函数"
  def __getitem__(self, item):
    return self.__dict__[item]
if __name__ == '__main__':
  a=A('lisa','123')
  print(a['name'])
  print(a[123])

输出


lisa
keyerror:123

上述修改后的代码输出了'lisa'和一个KeyError异常。具体而言,self.__dict__获取了当前实例所有属性的字典,通过[item]键取值。传入'name'时,成功获取了对应的属性值'lisa';而传入'123'时,由于该属性不存在,触发了KeyError。这是字典内部实现机制的一部分,也是__getitem__常见的应用场景。

再来看一个例子,代码里已经加入了注释:

__len__获取对象长度


import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
# 具名元组动态创建一个类Card,并含有两个属性rank和suit
# 用以构建只有少数属性但是没有方法的对象

class FrenchDeck:
  ranks = [str(n) for n in range(2, 11)] + list('JQKA') # 扑克牌2到A组成的列表
  suits = 'spades diamonds clubs hearts'.split() # 四种花色

  def __init__(self):
    self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] # 笛卡尔积,13*4=52(除去两个王)

  def __len__(self):
    return len(self._cards)

  def __getitem__(self, position):
    # 调用f[0]时会进入
    return self._cards[position]
if __name__ == '__main__':
  f = FrenchDeck()

  print(f[0])
  # 在这里f[0]实际是f.__getitem__(0)

输出


Card(rank='2', suit='spades')

在这个例子中,我们还看到了__len__方法的使用。那么,__len__方法的作用是什么呢?我们继续往下看。

__len__

在上面的例子中,我们使用了__len__方法。该方法在何时被调用呢?通过一个小例子来说明。

class B():


class B():
  def __init__(self):
    self.a_list = range(10)
  def __len__(self):
    return len(self.a_list)
if __name__ == '__main__':
   b = B()
   print(len(b))
   #在这里等价于
   #print(b.__len__())

输出


10

当调用内置的len()函数时,Python会自动调用对象的__len__方法。

__setitem__实现属性赋值

__setitem__

__setitem__(self, key, value)方法用于按特定方式存储与key相关的value。在设置类实例属性时,如果通过类似字典的方式赋值,会自动调用此方法。

class B():


class B():
  def __init__(self):
    self.a_list = range(10)
  def __setitem__(self, key, value):
    self.__dict__[key] = value
def cfun(a, b, c):
  print("新加入函数c")
if __name__ == '__main__':
  b = B()
  b['a_list'] = "123" # 这个会调用B类的\__setitem_方法_
  B.__setitem__ = cfun # 改变settime方式变为cfun这个函数
  b['a_list'] = "123" # 这次实际会调用cfun函数
  print(b.a_list)

输出


新加入函数c
123

__delitem__与__eq__方法

__delitem__

执行del函数时会调用__delitem__。如果类继承了abc.MutableSequence,则必须实现__delitem__方法,因为这是MutableSequence类定义的一个抽象方法,用于支持删除操作。

__eq__

表达式a == b等同于调用a.__eq__(b)。你可以在自己的类中定义__eq__方法,以自定义实例之间的相等比较逻辑。如果不覆盖__eq__,则使用从object继承的默认行为,即比较内存地址。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。