__str__和__repr__

Python 中的 __str__ 与 __repr__ 到底有什么差异

 

 

不少时候咱们本身编写一个类,在将它的实例在终端上打印或查看的时候,咱们每每会看到一个不太满意的结果。编码

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

因此,咱们可能会手动打印对象的一些属性或者是在类里本身实现一个方法来返回咱们须要的信息。命令行

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

使用 __str__ 实现类到字符串的转化代码规范

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

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

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

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

有了 __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__ 方法的实现。

相关文章
相关标签/搜索