很多时候我们自己编写一个类,在将它的实例在终端上打印或查看的时候,我们往往会看到一个不太满意的结果。

类默认转化的字符串基本没有我们想要的一些东西,仅仅包含了类的名称以及实例的 ID (理解为 Python 对象的内存地址即可)。虽说这总比没有好,但确实是没什么用处啊。

所以,我们可能会手动打印对象的一些属性或者是在类里自己实现一个方法来返回我们需要的信息。

这没有什么不对的地方,但是我们可以使用更 Pythonic 的方式来解决这个问题。

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

不用自己另外定义一个方法,和 JAVA 的 toString() 方法类似,你可以在类里实现__str__ 和 __repr__ 方法从而自定义类的字符串描述,这两种都是比较 Pythonic 的方式去控制对象转化为字符串的方式。

下面我们通过做实验慢慢的来看这两种方式是怎么工作的。首先,我们先加一个 __str__ 方法到前面的类中看看情况。

当你重新打印和查看这个类的实例的时候,你会看到一个稍微不同的结果

查看 my_car 的时候的输出仍然和之前一样,不过打印 my_car 的时候返回的内容和新加的 __str__ 方法的返回一致。类的 __str__ 方法会在某些需要将对象转为字符串的时候被调用。比如下面这些情况

有了 __str__ 这个方法,你就不用手动去打印对象的一些信息或者添加额外的方法去达到目的。类到字符串的转化使用 __str__ 这种 Pythonic 的方式实现即可。

使用 __repr__ 也有类似的效果

有的朋友可能发现,上面我们查看 my_car 对象的时候,输出的仍是类似 <__main__.Car object at 0x10b142128> 这样比较奇怪的结果。这是因为 Python 3 中一共有 2 中方式控制类到字符串的转化,第一种就是我们前面提到的 __str__ 方法,另一个就是 __repr__ 方法。后者的工作方式与前者类似,但是它被调用的时机不同。

Python 2 中还有一个 __unicode__ 方法,后面我会说明,暂时跳过。

这里有个简单的例子,同样是在之前的类上作改动

我们通过下面的操作来感觉下什么时候调用 __str__ ,什么时候调用的 __repr__ 。

从上面可以看出,当我们查看对象的时候(上图的最后一个操作)调用的是 __repr__ 方法。

另外,列表以及字典等容器总是会使用 __repr__ 方法。即使你显式的调用 str 方法,也是如此。

如果我们需要显示的指定以何种方式进行类到字符串的转化,我们可以使用内置的 str() 或 repr() 方法,它们会调用类中对应的双下划线方法。(当然,上面的情况除外)

当然,如果你直接调用 __str__ 或 __repr__ 方法,也能达到同样的方法,但是不推荐这么做。

那么 __str__ 和 __repr__ 的差别是什么

现在你可能在想,__str__ 和 __repr__ 的差别究竟在哪里,它们的功能都是实现类到字符串的转化,它们的特定并没有体现出用途上的差异。

带着这个这个问题,我们试着去 Python 的标准库中找找答案。我们就来看看 datetime.date 这个类是怎么在使用这两个方法的。

因此,我们有个初步的答案。

__str__ 的返回结果可读性强。也就是说,__str__ 的意义是得到便于人们阅读的信息,就像上面的 '2018-04-03' 一样。

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

上面应该就是这两个方法的意义所在吧(便于描述,后面我称这为通常的原则吧)。

但是于个人来说,如果按照通常的原则去编写代码会做很多额外的工作,两个方法的返回结果只需要对开发者友好就可以了,并不一定需要存储某个对象的完整状态。后面我会根据这一点,写部分有实践意义的代码实例,并不完全按照通常的原则。

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

如果你没有添加 __str__ 方法,Python 在需要该方法但找不到的时候,它会去调用 __repr__ 方法。因此,我推荐在写自己的类的时候至少添加一个 __repr__ 方法,这能保证类到字符串始终有一个有效的自定义转换方式。

我们为 Car 类添加一个 __repr__ 方法

注意,我们这里用了 !r 标记,是为了保证 self.color 与 self.mileage 在转化为字符串的时候使用 repr(self.color) 和 repr(self.mileage) ,而不是 str(self.color) 和 str(self.mileage) 。

这个能正常工作,不过有个缺点,就是我们把类的名称写死了。这有一个小技巧可以改进这种方式,就是使用对象的 __class__.__name__ 属性,该属性总代表着类的名称。

这样做的话,当类名被修改的时候,我们不需要修改 __repr__ 方法,这也符合软件开发的 DRY 原则( Don’t Repeat Yourself )。

这种写法也有一个不好的地方,就是格式化字符串太长了。当然,我们好好调整一个格式也能符合 PEP 8 的代码规范。

实现了 __repr__ 方法后,当我们查看类的实例或者直接调用 repr() 方法,就能得到一个比较满意的结果了。

打印或直接调用 str() 方法也能得到相同的结果,因为 __str__ 的默认实现就是调用 __repr__ 方法。

这样就能以比较少的工作量,让两个方法都能工作,并且也有一定的可读性,所以一般情况下,我都推荐至少添加一个 __repr__ 方法。

下面是比较全的代码示例

Python 2 中的 __unicode__ 方法

Python 3 中字符串用 str 类型表示,代表 unicode 字符串。而 Python 2 中字符串有两种类型,一是 str ,只能存储 ASCII 码,另一种是 unicode ,与 Python 3 中的 str 等同。

通常来说,用 __unicode__ 来控制类到字符串的转化更容易被大家接受。和 __str__ 和 __repr__ 类似,你可以使用内置的 unicode() 来显示调用 __unicode__ 方法。

打印语句和 str() 会调用 __str__ 方法,unicode() 会先找 __unicode__ 方法,找不到的话会调用 __str__ 方法,并将其结果按当时的编码方式解码返回。

相对于Python 3 ,Python 2 中的类到字符串的转化,显得稍微复杂一些。不过,下面我给了个便于实践的思路。由于使用 unicode 处理字符串更方便,这也是趋势,所以我们总会实现自己的 __unicode__ 方法。同时,__str__ 方法的实现则依靠于 __unicode__ ,主要逻辑是调用 __unicode__ 方法并将其结果使用 UTF-8 编码后返回。

所以,大部分情况下,__str__ 方法都不需要做修改,对于新建的类,可以直接把这个 __str__ 方法复制进去,而把关注点只放在 __unicode__ 方法的实现上。

下面是在 Python 2 中一段比较完整的示例

小结

* 我们可以使用 __str__ 和 __repr__ 方法定义类到字符串的转化方式,而不需要手动打印某些属性或是添加额外的方法。

* 一般来说,__str__ 的返回结果在于强可读性,而 __repr__ 的返回结果在于准确性。

* 我们至少需要添加一个 __repr__ 方法来保证类到字符串的自定义转化的有效性,__str__ 是可选的。因为默认情况下,在需要却找不到 __str__ 方法的时候,会自动调用 __repr__ 方法。

* 在 Python 2 中,我们可能更在意类的 __unicode__ 方法的实现。

转载于:https://www.cnblogs.com/yanyufeng/p/9617209.html

Python 中的 __str__ 与 __repr__ 到底有什么差别相关推荐

  1. python中class __str__怎么用_python中下划线的作用

    学习python的时候,我们经常碰到一些变量的变量名带单下划线/双下划线前缀或者后缀,然后会觉得这样的命名风格很奇怪.除了变量命名风格外,也会遇到下划线的表达式,也会让人摸不着头脑.今天我们就来看下, ...

  2. python中的__str__ __name__ 和__call__方法

    通过__str__( )函数可以打印对象的属性信息,方便我们调试代码. #通过__str__( )函数可以打印对象的属性信息,方便我们调试代码.class aa(object):def __init_ ...

  3. python中的装饰器有哪些-Python中的@函数装饰器到底是什么?

    在解释@函数装饰器之前,先说一下,类中的类方法和静态方法. 在Python中完全支持定义类方法.静态方法.这两种方法很相似,Python它们都使用类来调用(ps:用对象调用也可以). 区别在于:Pyt ...

  4. (转)python中的*args和**kw到底是个啥。看下面的例子就会懂了

    先来看个例子: def foo(*args, **kwargs):print 'args = ', argsprint 'kwargs = ', kwargsprint '-------------- ...

  5. python魔法方法中的__str__和__repr__区别

    __str__(self): class Test1():def __str__(self):return 'I am __str__' #return即返回什么打印什么 >>>a ...

  6. python中的__call__和__repr__魔术方法

    __call__:实现了__call__的对象是可调用的 __repr__:实现了__repr__的对象可以输出对象的相应属性信息 比如说: class Student:def __init__(se ...

  7. Python中的 if __name__ == __main__到底是个啥意思?

    对于Python初学者来说,在看别人代码时经常会看到if __name__ == "__main__",这时心里就开始吐槽:"绝对又是装逼,我特么不写这句话,代码不照样跑 ...

  8. __Str__和__repr__有什么区别?

    文章来源:__Str__和__repr__有什么区别? - 代码领悟code05.com 提问:__Str__和__repr__有什么区别? Python中的__str__和__repr__有什么区别 ...

  9. python中的str方法和repr方法_Python中 的 __str__ 方法和 __repr__ 方法的区别有哪些

    Python中 的 __str__ 方法和 __repr__ 方法的区别有哪些 发布时间:2020-11-05 17:11:48 来源:亿速云 阅读:95 作者:Leah 本篇文章给大家分享的是有关P ...

  10. python中 __str__和__repr__

    如果要把一个类的实例变成 str,就需要实现特殊方法__str__(): class Person(object):def __init__(self, name, gender):self.name ...

最新文章

  1. python实现STM32单片机通信
  2. java完全解耦_java-完全解耦 - osc_bc7dotjc的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. 苹果cms8x缩图带3D翻转自适应模版
  4. 数据处理-Batch Normalization
  5. 提高千倍效率的35个编码小技巧,老司机带你飞!
  6. Linux C基础笔记(1)
  7. property.js
  8. JS中比較2个字符串内元素的不同(字符1, 字符2, 分隔符可选)
  9. c51语言花样流水灯汇编程序,基于51单片机的各种花样的流水灯c51程序
  10. 深入解读Docker底层技术cgroup系列(1)——cgroup介绍
  11. 2022华为软挑赛题讲解(CodeCraft-2022)
  12. java9 32位官网下载_jdk1.9 32位官方下载
  13. 计算机发展变化英文作文60词,生活中的变化英文作文(精选4篇)
  14. pcl计算点云法向量
  15. Android Q 适配详细操作
  16. javax.net.ssl.SSLHandshakeException: Unacceptable certificate: CN=GeoTrust SSL C
  17. 毕业之后所有面试总结
  18. 也议:程序员想要什么样的上司
  19. java语言商场打折_Java封装商场打折策略(Strategy模式)
  20. JDK7新特性_JDK7的六个新特性

热门文章

  1. LINUX下载编译OpenAL Soft
  2. 解决办法:undefined reference to symbol 'shm_open@@GLIBC_2.2.5'
  3. 时空解析理论的实验检验方法
  4. SHELL中函数的写法、调用、参数、返回值代码范例
  5. priority_queue的优先级设置
  6. ai画面怎么调大小_AI人脸抓拍摄像机安装指导,这样安装抓拍更准
  7. hiveserver2启动不起来_125踏板车电启动发不着时,为什么很少用户使用脚启动?...
  8. 递归求n的阶乘不溢出_面试官:说一说递归如何优化尾递归优化
  9. java多肽跟重载_Java多态vs重写vs重载
  10. mysql中乘积函数_Mysql中的函数