很多时候我们在创建一个类的时候,在终端打印类或者查看的时候一般都不会得到一个太满意的结果

class T:
  def __init__(self):
self.color="red"
self.count = 2
t = T()
t
>>> <T object at 0x0000000003444E10>
print(t)
>>> <T object at 0x0000000003444E10>

类转化为字符串,直接打印结果一般都不是我们想要的东西,仅仅包含了类的名称以及实例的 ID (理解为 Python 对象的内存地址即可),例如<T object at 0x0000000003444E10> ,这样类默认转化为字符串根本不能得到我们想要的关于属性信息等的相关东西,只能通过手动打印才能进一步获取到更多的信息,例如print(t.color)

使用 __str__ 实现类到字符串的转化   

不用自己另外的定义方法,和java的toString的方法类似,可以在类里面实现__str__和__repr__方法,从而自已定义类的字符串描述,下面具体看看这两种方式是怎么工作的。

首先,我们先加一个 __str__ 方法到前面的类中看看情况。

class T:
def __str__(self):
return self.color+"__str__"
def __init__(self):
self.color="red"
self.count = 2
t = T()
t
>>> <T object at 0x0000000003444E10>
print(t)
>>> red__str__

查看 t的时候的输出仍然和之前一样,输出内存地址信息,不过打印 t的时候返回的内容和新加的 __str__ 方法的返回一致。类的 __str__ 方法会在某些 需要将对象转为字符串的时候被调用。

比如下面这些情况,需要将对象转为字符串

print(t)
print(str(t))
print("{}".format(t))

使用 __repr__ 也有类似的效果 

会发现,在使用__str__方法的时候,直接在终端查看t对象的时候,输出的时候仍然是内存地址,这是因为在python3中有两种方式控制对象转字符串,第一种就是__str__,第二种就是__repr__,两种的工作方式大体相同,只是调用的时机不同。下面通过一个简单的例子看看__repr__方法

class T:
def __repr__(self):
return self.color+"__repr__"
def __str__(self):
return self.color+"__str__"
def __init__(self):
self.color="red"
self.count = 2
t = T()
t
>>> red__repr__
print(t)
>>> red__str__
print(str(t))
>>> red__str__
print("{}".format(t))
>>> red__str__
print(str(["d","f",t]))
>>> ['d', 'f', red__repr__]

通过如上的例子可以看出,当直接查看对象的时候调用的是__repr__方法,对象需要转字符串的时候调用的是__str__方法,但是当字典列表等容器的时候调用的还是__repr__方法

如果我们需要显示的指定以何种方式进行类到字符串的转化,我们可以使用内置的 str() 或 repr() 方法,它们会调用类中对应的双下划线方法。除了字典、列表等作为容器的时候print(str(["d","f",t])),虽然调用的是str()方法,可是容器是列表,所以对象t转为字符串时调用的就是__repr__

__str__ 和 __repr__ 的差别 

那么他们的区别具体的在哪里,带着这个问题我们python的标准库, 其中datetime.date 这个类是怎么在使用这两个方法的。

import datetime
today = datetime.datetime.today()
print(str(today))
>>> 2019-10-20 20:59:47.003003
print(repr(today))
>>> datetime.datetime(2019, 10, 20, 20, 59, 47, 3003)

__str__ 的返回结果可读性强。也就是说,__str__ 的意义是得到便于人们阅读的信息,就像上面的 '2019-10-20 20:59:47.003003' 一样。

__repr__ 的返回结果应更准确。怎么说,__repr__ 存在的目的在于调试,便于开发者使用。将 __repr__ 返回的方式直接复制到命令行上,是可以直接执行的。

 为什么每个类都最好有一个 __repr__ 方法

如果你想保证每个类到字符串都有一个有效的自定义转换方式,你需要重写__str__或者__repr__中的一个方法,如果没有写__str__方法,python就会去找__repr__方法,所以至少添加一个

class T:
def __repr__(self):
return (self.color)
def __init__(self,color):
self.color = color
t = T("red")
print(t)
>>> red
t
>>> red
print(str(t))
>>> red

实现了 __repr__ 方法后,当我们查看类的实例或者直接调用 repr() 方法,就能得到一个比较满意的结果了。打印或直接调用str()等类转字符串的操作都会得到相同的结果,因为__str__的默认实现就是调用__repr__方法。

这样就能用比较少的工作量,不用手动的去一一获取信息,就能让两个方法都能功能,而且都具有一定的可读性,所以推荐类中至少添加一个__repr__ 方法。
小结
  • 我们可以使用__str__ 和 __repr__中的任意一个方法定义类到字符串的转化方式,不需要手动的打印某些属性和一些额外的信息
  • 一般来说__str__的可读性更强,而__repr__的返回结果更具有准确性,更加的适合开发者
  • 我们在写类的时候,最好至少添加一个__repr__方法,来保证类到字符串的转换具有自定义的有效性,__str__是可选的,因为在默认情况下,__Str__方法默认实现调用的是__repr__方法,所以在对象转字符串时候,找到底层str方法之后,会调用重写的__repr__方法

也就是说,

  直接查看字符串的时候调用的是__repr__方法;

  对象在转字符串的时候:如果容器是字典或者列表调用的是__repr__方法;如果是其他情况则默认调用的是底层的__Str__方法。__str__如果被重写调用的则是重写之后__Str__,就和__repr__没有关系了,如果没有被重写,则调用的是底层__str__方法,底层方法默认实现方式是调用了__repr__ 方法,之后查看__repr__是否被重写,重写则调用重写之后的,否则调用底层的__repr__,最后执行转为字符串

  如果打印str(t)则默认调用的是__str__,如果直接打印repr(t)则默认调用的是__repr__方法

浅谈python中__str__和__repr__的区别的更多相关文章

  1. python中__str__与__repr__的区别

    __str__和repr __str__和__repr__都是python的内置方法,都用与将对象的属性转化成人类容易识别的信息,他们有什么区别呢 来看一段代码 from math import hy ...

  2. Python中__str__和__repr__的区别

    Python有一个内置的函数叫repr,它能把一个对象用字符串的形式表达出来以便辨认,这就是“字符串表示形式”.repr就是通过__repr__这个特殊方法来得到一个对象的字符串表示形式.如果没有实现 ...

  3. 浅谈Python 中 __getattr__与__getattribute__的区别

    __getattr__与__getattribute__均是一般实例属性截取函数(generic instance attribute interception method),其中,__getatt ...

  4. 浅谈Python中的深浅拷贝的区别

    深.浅拷贝总结 深拷贝 拷贝可变数据类型,如列表容器: a = [1, 2, [3, 4]] b = copy.deepcopy(a) a 与 b 所指的列表容器的空间地址不一致,即 id(a) != ...

  5. 转 浅谈C++中指针和引用的区别

    浅谈C++中指针和引用的区别 浅谈C++中指针和引用的区别   指针和引用在C++中很常用,但是对于它们之间的区别很多初学者都不是太熟悉,下面来谈谈他们2者之间的区别和用法. 1.指针和引用的定义和性 ...

  6. 浅谈 HTTP中Get与Post的区别

    浅谈 HTTP中Get与Post的区别 存在的误区 有人说 HTTP 协议下的 Get 请求参数长度是有大小限制的,最大不能超过XX,而 Post 是无限制的,看到这里,我想他们定是看多了一些以讹传讹 ...

  7. 浅谈Java中set.map.List的区别

    就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...

  8. python中__str__与__repr__

    (1)背景 python中,对于类(自定义类)的实例对象的默认显示既没有太大用处,也不美观.比如: class adder: def __init__(self,value=0): self.data ...

  9. 浅谈python中得import xxx,from xxx import xxx, from xxx import *

    在python中import跟from import都是用来导入的,但是导入的机制不同 1.import xxx:导入模块,或者文件夹,对于调用模块或者文件夹中子模块的变量或者函数,需要使用" ...

随机推荐

  1. WEB-INF目录与META-INF目录的作用(转载)

    /WEB-INF/web.xml Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则. /WEB-INF/classes/包含了站点所有用的 class 文件,包括 ser ...

  2. docker跨主机链接

    三种方式 一,使用网桥实现跨主机容器连接

  3. 题解【洛谷P1807】最长路_NOI导刊2010提高(07)

    题面 题解 最长路模板. 只需要在最短路的模板上把符号改一下\(+\)初值赋为\(-1\)即可. 注意一定是单向边,不然出现了正环就没有最长路了,就好比出现了负环就没有最短路了. 只能用\(SPFA\ ...

  4. 杭电ACM 1713 相遇周期

    相遇周期 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  5. Centos7 FRPS

    #下载Sever端 wget https://github.com/fatedier/frp/releases/download/v0.16.1/frp_0.16.1_linux_amd64.tar. ...

  6. 问题 B: 奇怪的电梯

    问题 B: 奇怪的电梯 时间限制: 1 Sec  内存限制: 128 MB[命题人:admin] 题目描述 大楼的每一层楼都可以停电梯,而且第i层楼(1<=i<=N)上有一个数字Ki(0& ...

  7. Web 安全工具篇:Burp Suite 使用指南

    真的是一点都不过分,了解详情请继续往下读. Burp Suite 介绍 Burp Suite 是用于攻击 web 应用程序的集成平台.它包含了许多工具,并为这些工具设计了许多接口,以促进加快攻击应用程 ...

  8. 虚拟函数是否应该被声明仅为private/protected?

    问题导入 我想对于大家来说,虚拟函数并不能算是个陌生的概念吧.至于怎么样使用它,大部分人都会告诉我:通过在子类中重写(override)基类中的虚拟函数,就可以达到OO中的一个重要特性——多态(pol ...

  9. SQL通过Datatable更新数据库表内容

    SQL通过Datatable更新数据库表内容   //要注意的一点是在Select语句中要选择的列中必须包含主键的列,此外不支持多表连接查询 DataTable dt = new DataTable( ...

  10. PHP获取用户的真实IP地址,非代理IP

    function getClientIP(){ global $ip; if(getenv("HTTP_CLIENT_IP")){ $ip = getenv("HTTP_ ...