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

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. Request功能

    1.获取请求消息数据 获取请求行数据 获取请求头数据 获取请求体数据 请求空行没必要获取 1.获取请求行数据 GET /虚拟目录 /servlet路径  ?请求参数 HTTP/1.1 GET/day1 ...

  2. jdk之java.lang.Integer源码理解

    基本数据类型的包装类java.lang.Integer是我们频繁使用的一个系统类,那么通过一个示例反应出的几个问题来深入理解一下此类的源码. 需求:实现Integer类型的两个数值交换. packag ...

  3. java+layui的Excel导入导出

    html: <button class="layui-btn" onclick="exportData();">导出</button> ...

  4. IDEAVIM 常用快捷键总结和使用说明

    ---title: ideavim常用快捷键总结和使用tags: grammar_cjkRuby: true--- #### `待办` ideavim用于编程的常用快捷键说明 常用快捷键 插入(光标前 ...

  5. Apache Kafka(六)- High Throughput Producer

    High Throughput Producer 在有大量消息需要发送的情况下,默认的Kafka Producer配置可能无法达到一个可观的的吞吐.在这种情况下,我们可以考虑调整两个方面,以提高Pro ...

  6. javaFx中Image的路径问题

    网络图像文件前面加“http://”,而本地文件则要加“file:”.将源代码改为: Image image = new Image("file:image/qq.jpg"); I ...

  7. 题解【CodeForces1154A】Restoring Three Numbers

    Description Polycarp has guessed three positive integers \(a\), \(b\) and \(c\). He keeps these numb ...

  8. D. Mahmoud and Ehab and another array construction task 因子分界模板+贪心+数学

    D. Mahmoud and Ehab and another array construction task 因子分解模板 题意 给出一个原序列a 找出一个字典序大于a的序列b,使得任意 \(i!= ...

  9. AC3 encoder flow

    AC3 encoder flow 如下: 1.input PCM PCM在进入encoder前会使用high pass filter来移除信号的DC部分来达到更有效的编码. 2.Transient d ...

  10. Python实现AVL树

    参考: https://www.cnblogs.com/linxiyue/p/3659448.html?utm_source=tuicool&utm_medium=referral class ...