Python中__repr__()和__str__()的异同

news2024/11/18 14:50:18

在学习类相关知识时,注意到了__str__()和__repr__()这两种方法,但对两者的异同不是很了解,因此写这篇博客记录一下学习过程,也供其他小伙伴参考。文中如有错误或者表述不当之处欢迎在评论区指出。

首先,__repr__()和__str__()都属于特殊方法(也称魔术方法,magic method),且作用都是根据对象的状态返回字符串。那两者的具体应用场景以及区别是什么呢?接下来一一进行介绍。


一、__str__()方法

1.  应用场景,即在什么时候会被调用

对象的__str__()方法在以下情况下会被调用:

  • 使用print()打印一个对象;
  • 将对象传入format()
  • 将对象传入str.format()
  • 将对象传入str()

注意:如果对象中定义了__str__()方法,则在上述情况下__str__()会被调用,否则将会调用__repr__()方法。

2. 默认实现

python中所有类默认会继承object类,object类中默认实现了__str__()和__repr__()方法,但由于python的源码是C语言,所以对于普通python用户来说阅读难度较大,在这里我们用python语言等价表示一下__str__()方法默认实现的原理:

# __repr__()默认实现同理
def __str__(self):
    return '<{0}.{1} object at {2}>'.format(
      type(self).__module__, type(self).__qualname__, hex(id(self)))

其中__module__()表示对象来自哪个模块,__qualname__()我们可以暂时理解为类的名字(__qualname__和__name__的异同感兴趣的伙伴可自行查阅)。

也就是说,object类中默认实现的__str__()方法会输出对象所在的模块对象所属的类的名字以及对象在内存中的十六进制地址表示

3. 实例分析

了解了__str__()的具体应用场景以及默认实现,接下来结合几个例子进一步理解一下具体的调用过程。

例子1:自定义类,但并未在类中实现__str__()方法。可以先回忆一下如果没有实现__str__()方法,情况会如何?

>>> class CustomClass: pass 
...
>>> print(CustomClass())  # 调用print()方法
<__main__.CustomClass object at 0x000001BFB5E13DC0>
>>> str(CustomClass())  # 调用str()方法
'<__main__.CustomClass object at 0x000001BFB5E13DC0>'

结合上述例子,我们分析一下具体的调用过程。首先我们定义了一个名为CustomClass的类,然后我们分别将它的一个实例对象传入print()和和str()方法中,这两种方法都是调用对象的__str__()方法;但是由于CustomClass中没有实现__str__()方法,那么根据注意事项中提到的,会调用__repr__()方法,但显然CustomClass中也没有实现,最终就会调用基类object中的__repr__()方法。

注意:print()和str()两者最终调用的都是object中的__repr__()方法,__repr__()返回的是字符串,但print()将字符串打印在了屏幕上,而str()保留了字符串的格式。

例子2:自定义类,但实现了__str__()方法。

>>> class CustomClass:     
...     def __str__(self): return 'foo' 
...
>>> print(CustomClass()) 
foo
>>> str(CustomClass()) 
'foo'

这个例子比较容易理解,就是调用了CustomClass类中实现的__str__()方法。

4. 目的

根据__str__()的具体使用场景我们可以看出,主要是print()、str()等函数会调用对象的__str__()方法,而print()、str()等函数的输出通常主要是给程序的使用者看的,且并非所有程序使用者都具有编程知识,所以__str__()的返回值一定是便于阅读的。这一点结合后面__repr__()的目的进行理解。


二、__repr__()方法

1. 应用场景

__repr__()方法调用场景主要有以下两种:

  • 被内置函数repr()调用;
  • 我们输入能返回一个对象的表达式时,回车之后在python shell中显示内容的过程会调用__repr__()方法。
  • debugger时的变量表示

__repr__()作为__str__()的备用方法,如果你只能实现其中一个的话,建议实现__repr__()方法。

2. 默认实现

同__str__()。

3. 案例分析

例子1:自定义类,但没有实现__repr__()方法。

>>> class C: pass
... 
>>> repr(C())
'<__main__.C object at 0x000001B277733DC0>'
>>> C()
<__main__.C object at 0x000001B277733DC0>

首先,我们自定义了一个名为C的类,在将C的实例对象传给repr()时,去调用C的__repr__()方法,但由于C中没有实现,最终调用的是基类object中的__repr__()方法。在解释器中输入C()回车后调用过程同理。

注意:当在控制台直接输入C()并按回车键时,调用__repr__()并得到一个字符串返回值,但为了提高可读性,解释器只显示了这个字符串的内容,没有加引号。

例子2:自定义类且实现__repr__()方法。

>>> class C:     
...     def __repr__(self): return 'call __repr__() method' 
... 
>>> repr(C()) 
'call __repr__() method'
>>> C()
call __repr__() method

4. 目的

根据__repr__()的应用场景——控制台输出、debugger等,可以看出,其输出的内容主要面向程序开发者,需要为开发者提供必要且有用的信息,包括但不限于对象对应的类名、对象属性值等。

我们结合一个例子直观感受一下为什么说__str__()主要面向程序使用者,而__repr__()主要面向程序开发者:

>>> import datetime 
>>> datetime.datetime.now()  # 调用__repr__()
datetime.datetime(2024, 11, 17, 22, 23, 18, 647770)
>>> print(datetime.datetime.now()) # 调用__str__()
2024-11-17 22:23:42.227722

因此对于__repr__()的返回值,我们希望其满足一定要求,具体来说就是:

eval(repr(object)) == object

其中eval()函数用来执行一个字符串表达式,并返回表达式的值。也就是说,一个对象__repr__()的返回值,如果在控制台输入这个返回值,可以得到一个对象实例。

结合例子具体理解一下:

# 定义一个表示二维向量的类
class Vector:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        s = 'Vector(%r, %r)' % (self.x, self.y)
        return s

在上述例子中,对于使用默认参数的对象实例Vector(),_repr__()返回值为‘Vector(0, 0)’,而eval()则会根据这个返回值再创建一个对象实例。

但__repr__()的默认实现并不满足上述要求,因此在编写大型项目时通常需要自行实现。


三、总结

最后总结一下__str__()和__repr__()两者的异同。

相同点

  • 都属于特殊方法;
  • 返回值都是字符串;
  • 在默认实现中,两者的返回值相同。

不同点

  • 应用场景不同,__str__()是当对象传入print()、str()、format()和str.format()时被调用,而__repr__()是对象传入repr()、控制台输出和debugger时被调用;
  • 输出内容面向人群不同,__str__()返回值主要是给程序使用者看的,而__repr__()返回值是给程序开发者看的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2242866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【更新中】《硬件架构的艺术》笔记(三):处理多个时钟

介绍 单时钟设计更易于实现&#xff0c;也更少出现亚稳态、建立和保持时间违例方面的问题。但在实践中&#xff0c;很少有设计只在一个时钟下运行。 多时钟域 多个始终可以有以下一种或多种时钟关系&#xff1a; 1、时钟频率不同。 2、时钟频率相同&#xff0c;但相位不同…

Python_爬虫1_Requests库入门

目录 Requests库 7个主要方法 Requests库的get()方法 Response对象的属性 爬取网页的通用代码框架 理解requests库的异常 HTTP协议及Requests库方法 HTTP协议 HTTP协议采用URL作为定位网络资源的标识。 HTTP协议对资源的操作 理解PATCH和PUT的区别 HTTP协议与Requse…

从客户需求视角去认识ZLG | 边缘计算网关多种应用

在工业领域&#xff0c;串行总线与EtherNET总线广泛应用&#xff0c;物联网的兴起带来众多智能应用。尽管应用多样&#xff0c;但底层技术逻辑却殊途同归&#xff0c;本文将介绍ZLG致远电子串行总线和EtherNET总线之间的联动应用。 本文将从系统集成需求出发&#xff0c;以ZLG致…

Koa进阶:掌握中间件和参数校验的艺术

目录 一、首先下载依赖 二、在index.js中引入koa-parameter&#xff0c;一般挂载这个中间件时会放在注册请求体的后面 三、使用实例 四、如果跟我们所需求的参数不同&#xff0c;返回结果直接会返回422 koa-parameter一般是用来校验请求传过来的参数是否是自己所需要的的 G…

Linux下使用miniconda构建python运行环境

文章目录 miniconda安装构建python运行环境 miniconda安装 miniconda在linux环境下载安装&#xff1a; # Linux环境下使用wget命令下载选定的miniconda # 这里使用的是清华镜像&#xff0c;这个命令每次下载的是最新版本的miniconda wget -c https://mirrors.tuna.tsinghua.e…

解决failed to execute PosixPath(‘dot‘) 或者GraphViz‘s executables not found

在网上找了很多方法都没解决&#xff0c;所以写一篇文章帮助和我遇到同样问题的人 解决方法&#xff1a; 因为python解释器会解释转移字符&#xff0c;因此在环境变量中把\bin换成\\bin即可 解决过程&#xff1a; 系统&#xff1a;win10 已安装pip install graphviz&#xff0…

Deep-Live-Cam -面部交换、视频深度伪造

文章目录 一、关于 Deep-Live-Cam免责声明 二、安装&#xff08;Windows/Nvidia&#xff09;安装&#xff08;手动&#xff09;基本安装&#xff08;CPU&#xff09; GPU加速&#xff08;可选&#xff09;CUDA执行提供商&#xff08;Nvidia&#xff09;CoreML执行提供商&#x…

计算机毕业设计Python美食推荐系统 美团爬虫 美食可视化 机器学习 深度学习 混合神经网络推荐算法 Hadoop Spark 人工智能 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Scala-数据类型-概述(Scala 3.x 类型层次结构)

Scala Scala-数据类型 Scala1. Any — 顶级类型2. Matchable — 匹配类型3. AnyVal — 值类型的父类4. AnyRef — 引用类型的父类5. Null - 引用类型的子类型Tips: 为什么 null 不推荐使用&#xff1f; 6. Nothing - 底层类型 (Bottom Type)整理不易&#xff0c;对您有帮助的话…

嵌入式linux中红外接收基本方法分析

大家好,今天主要给大家分享一下,如何使用Linux系统中的红外接收驱动控制方法。 第一:Linux红外基本简介 红外遥控是我们常见的一种无线收发设备,具有抗干扰能力强,功耗低,成本低,易实现等优点。被很多电子设备特别是家用电器广泛采用,如电视遥控、空调遥控等。红外遥控…

AWTK-WIDGET-WEB-VIEW 实现笔记 (2) - Windows

在 Windows 平台上的实现&#xff0c;相对比较顺利&#xff0c;将一个窗口嵌入到另外一个窗口是比较容易的事情。 1. 创建窗口 这里有点需要注意&#xff1a; 父窗口的大小变化时&#xff0c;子窗口也要跟着变化&#xff0c;否则 webview 显示不出来。创建时窗口的大小先设置…

pgAdmin简单介绍

pgAdmin介绍 官网&#xff1a;https://www.pgadmin.org/ pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world. pgAdmin may be used on Linux, Unix…

Linux笔记---调试工具GDB(gdb)

1. gdb的概念 GDB&#xff0c;全称GNU Debugger&#xff0c;是一个功能强大的开源调试工具&#xff0c;广泛用于Unix和类Unix系统&#xff0c;以及Microsoft Windows和macOS平台。GDB允许开发者在程序执行过程中查看内部运行情况&#xff0c;帮助定位和修复程序中的错误。 gd…

如何在 Ubuntu 上安装 Mattermost 团队协作工具

简介 Mattermost 是一个开源、自托管的通信平台&#xff0c;专为团队协作设计。它类似于 Slack&#xff0c;提供聊天、消息传递和集成功能。Mattermost 在重视数据隐私的组织中特别受欢迎&#xff0c;因为它允许团队在自己的服务器上管理通信。以下是 Mattermost 的一些关键特…

2. Django中的URL调度器 (自定义路径转换器)

在 Django 中&#xff0c;URL 路由通常使用路径转换器&#xff08;path converters&#xff09;来匹配和捕获 URL 中的特定模式&#xff0c;例如整数、字符串或 slug 等。默认情况下&#xff0c;Django 提供了一些内置的路径转换器&#xff0c;如 <int>、<str>、&l…

【STM32】USB 简要驱动软件架构图

STM32 USB 软件架构比较复杂&#xff0c;建议去看 UM 1734 或者 st wiki STM32 USB call graph STM32 USB Device Library files organization Reference [1]: https://wiki.stmicroelectronics.cn/stm32mcu/wiki/Introduction_to_USB_with_STM32 [2]: UM1734

MATLAB 使用教程 —— 命令窗口输入命令,工作区显示变量

命令在命令窗口输入变量在工作区显示 MATLAB 桌面包含的面板如下&#xff1a; 当前文件夹 - 此面板允许访问项目文件夹和文件。命令窗口 - 这是主要区域&#xff0c;用户在命令行中输入命令&#xff0c;命令提示符(>>).工作区 - 工作区显示所有变量&#xff0c;无论是创…

华为USG5500防火墙配置NAT

实验要求&#xff1a; 1.按照拓扑图部署网络环境&#xff0c;使用USG5500防火墙&#xff0c;将防火墙接口加入相应的区域&#xff0c;添加区域访问规则使内网trust区域可以访问DMZ区域的web服务器和untrust区域的web服务器。 2.在防火墙上配置easy-ip&#xff0c;使trust区域…

时钟之CSS+JS版

写在前面 此版本绘制的时钟基于CSSJS模式。 优点操作简单&#xff0c;缺点当然是不够灵活。下一篇会基于HTML5的canvas标签&#xff0c;使用JS绘制。会更灵活&#xff0c;元素更加丰富。 HTML代码 <div class"box"><article class"clock"><…

blender 骨骼的动画基础 笔记总结

一、世界纹理 1.首先打开Node Wrangler&#xff08;世界纹理&#xff09;插件 在编辑的偏好设置这里&#xff0c; 演示一下这个插件&#xff1a; 然后通过shift a添加环境纹理 对其连接颜色后&#xff0c;选中世界纹理&#xff0c;通过按键ctrl t 二、动画 点击动画 1.…