《Python面向对象编程指南》——第2章 与Python无缝集成——基本特殊方法 2.1 __repr__()和__str__()方法

简介:

本节书摘来自异步社区《Python面向对象编程指南》一书中的第2章,第2.1节,作者[美]Steven F. Lott, 张心韬 兰亮 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

第2章 与Python无缝集成——基本特殊方法

Python中有一些特殊方法,它们允许我们的类和Python更好地集成。在标准库参考(Standard Library Reference)中,它们被称为基本特殊方法,是与Python的其他特性无缝集成的基础。

例如,我们用字符串来表示一个对象的值。Object基类包含了__repr__()和__str__()的默认实现,它们提供了一个对象的字符串描述。遗憾的是,这些默认的实现不够详细。我们几乎总会想重写它们中的一个或两个。我们还会介绍__format__(),它更加复杂一些,但是和上面两个方法的作用相同。

我们还会介绍其他的转换方法,尤其是__hash__()、__bool__()和__bytes__()。这些方法可以把一个对象转换成一个数字、一个布尔值或者一串字节。例如,当我们实现了__bool__(),我们就可以像下面这样在if语句中使用我们的对象:if someobject:。

接下来,我们会介绍实现了比较运算符的几个特殊方法:__lt__()、__le__()、__eq__()、__ne__()、__gt__()和__ge__()。

当我们定义一个类时,几乎总是需要使用这些基本的特殊方法。

我们会在最后介绍__new__()和__del__(),因为它们的使用更加复杂,而且相比于其他的特殊方法,我们并不会经常使用它们。

我们会详细地介绍如何用这些特殊方法来扩展一个简单类。我们需要了解从object继承而来的默认行为,这样,我们才能理解应该在什么时候使用重写,以及如何使用它。

2.1 __repr__()和__str__()方法

对于一个对象,Python提供了两种字符串表示。它们和内建函数repr()、str()、print()及string.format()的功能是一致的。

  • 通常,str()方法表示的对象对用户更加友好。这个方法是由对象的__str__方法实现的。
  • repr()方法的表示通常会更加技术化,甚至有可能是一个完整的Python表达式。文档中写道:

对于大多数类型,这个方法会尝试给出和调用eval()一样的结果。

这个方法是由__repr__()方法实现的。

  • print()函数会调用str()来生成要输出的对象。
  • 字符串的format()函数也可以使用这些方法。当我们使用{!r}或者{!s}格式时,我们实际上分别调用了__repr__()或者__str__()方法。

下面我们先来看一下这些方法的默认实现。

下面是一个很简单的类。

class Card:
   insure= False
   def __init__( self, rank, suit ):
     self.suit= suit
     self.rank= rank
     self.hard, self.soft = self._points()
class NumberCard( Card ):
   def _points( self ):
     return int(self.rank), int(self.rank)

我们定义了两个简单类,每个类包含4个属性。

下面是在命令行中使用NumberCard类的结果。

>>> x=NumberCard( '2', '')
>>>str(x)
'<__main__.NumberCard object at 0x1013ea610>'
>>>repr(x)
'<__main__.NumberCard object at 0x1013ea610>'
>>>print(x)
<__main__.NumberCard object at 0x1013ea610>

可以看到,__str__()和__repr__()的默认实现并不能提供非常有用的信息。

在以下两种情况下,我们可以考虑重写__str__()和__repr__()。

  • 非集合对象:一个不包括任何其他集合对象的“简单”对象,这类对象的格式化通常不会特别复杂。
  • 集合对象:一个包含集合的对象,这类对象的格式化会更为复杂。

2.1.1 非集合对象的__str__()和__repr__()

正如我们在前面看到的,__str__()和__repr__()并没有提供有用的信息,我们几乎总是需要重载它们。下面是当对象中不包括集合时我们可以使用的一种方法。这些方法是我们前面定义的Card类的方法。

   def __repr__( self ):
     return "{__class__.__name__}(suit={suit!r}, rank={rank!r})".
format(
       __class__=self.__class__, **self.__dict__)
   def __str__( self ):
     return "{rank}{suit}".format(**self.__dict__)

这两个方法依赖于如何将对象的内部实例变量__dict__传递给format()函数。这种方式对于使用__slots__的函数并不合适,通常来说,这些都是不可变的对象。在格式规范中使用名字可以让格式化更加可读,不过它也让格式化模板更长。以__repr__()为例,我们传递了__dict__和__class__作为format()函数的参数。

格式化模板使用了两种格式化的规范。

  • {__class__.__name__}模板,有时候也被写成{__class__.__name__!s},提供了类名的简单字符串表示。
  • {suit!r}和{rank!r}模板,它们都使用了!r格式规范来给repr()方法提供属性值。

以__str__()为例,我们只传递了对象的__dict__,而内部则是隐式使用了{!s}格式规范来提供str()方法的属性值。

2.1.2 集合中的__str__()和__repr__()

涉及集合的时候,我们需要格式化集合中的单个对象以及这些对象的整体容器。下面是一个包含__str__()和__repr__()的简单集合。

class Hand:
   def __init__( self, dealer_card, *cards ):
     self.dealer_card= dealer_card
     self.cards= list(cards)
   def __str__( self ):
     return ", ".join( map(str, self.cards) )
   def __repr__( self ):
     return "{__class__.__name__}({dealer_card!r}, {_cards_str})".
format(
     __class__=self.__class__,
     _cards_str=", ".join( map(repr, self.cards) ),
     **self.__dict__ )

__str__()方法很简单。

1.调用map函数对集合中的每个对象使用str()方法,这会基于返回的字符串集合创建一个迭代器。

2.用",".join()将所有对象的字符串表示连接成一个长字符串。

__repr__()方法更加复杂。

1.调用map函数对集合中的每个对象应用repr()方法,这会基于返回的结果集创建一个迭代器。

2.使用".".join()连接所有对象的字符串表示。

3.用__class__、集合字符串和__dict__中的不同属性创建一些关键字。我们将集合字符串命名为_card_str,这样就不会和现有的属性冲突。

4.用"{__class__.__name__}({dealer_card!r}, {_cards_str})".format()来连接类名和之前连接的对象字符串。我们使用!r格式化来保证属性也会使用repr()来转换。

在一些情况下,我们可以优化这个过程,让它更加简单。在格式化中使用位置参数可以在一定程度上简化模板字符串。

相关文章
|
3月前
|
机器学习/深度学习 Python
堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能
本文深入探讨了堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能。文章详细介绍了堆叠的实现步骤,包括数据准备、基础模型训练、新训练集构建及元学习器训练,并讨论了其优缺点。
129 3
|
4月前
|
前端开发 JavaScript UED
探索Python Django中的WebSocket集成:为前后端分离应用添加实时通信功能
通过在Django项目中集成Channels和WebSocket,我们能够为前后端分离的应用添加实时通信功能,实现诸如在线聊天、实时数据更新等交互式场景。这不仅增强了应用的功能性,也提升了用户体验。随着实时Web应用的日益普及,掌握Django Channels和WebSocket的集成将为开发者开启新的可能性,推动Web应用的发展迈向更高层次的实时性和交互性。
124 1
|
14天前
|
存储 人工智能 Python
[oeasy]python061_如何接收输入_input函数_字符串_str_容器_ 输入输出
本文介绍了Python中如何使用`input()`函数接收用户输入。`input()`函数可以从标准输入流获取字符串,并将其赋值给变量。通过键盘输入的值可以实时赋予变量,实现动态输入。为了更好地理解其用法,文中通过实例演示了如何接收用户输入并存储在变量中,还介绍了`input()`函数的参数`prompt`,用于提供输入提示信息。最后总结了`input()`函数的核心功能及其应用场景。更多内容可参考蓝桥、GitHub和Gitee上的相关教程。
11 0
|
4月前
|
Java C# Python
Python学习七:面向对象编程(中)
这篇文章是关于Python面向对象编程的中级教程,涵盖了析构函数、对象的三大特征(封装、继承、多态)、类属性与实例属性、以及类方法与静态方法的对比。
45 2
|
4月前
|
设计模式 安全 JavaScript
Python学习八:面向对象编程(下):异常、私有等
这篇文章详细介绍了Python面向对象编程中的私有属性、私有方法、异常处理及动态添加属性和方法等关键概念。
40 1
|
4月前
|
Go C++ Python
Python Tricks: String Conversion(Every Class Needs a ___repr__)
Python Tricks: String Conversion(Every Class Needs a ___repr__)
30 5
|
4月前
|
SQL 机器学习/深度学习 数据库
SQL与Python集成:数据库操作无缝衔接
在开始之前,确保你已经安装了必要的Python库,如`sqlite3`(用于SQLite数据库)或`psycopg2`(用于PostgreSQL数据库)。这些库提供了Python与SQL数据库之间的接口。
|
5月前
|
存储 Java 程序员
30天拿下Python之面向对象编程
30天拿下Python之面向对象编程
26 3
|
4月前
|
SQL 机器学习/深度学习 数据采集
SQL与Python集成:数据库操作无缝衔接2a.bijius.com
Python与SQL的集成是现代数据科学和工程实践的核心。通过有效的数据查询、管理与自动化,可以显著提升数据分析和决策过程的效率与准确性。随着技术的不断发展,这种集成的应用场景将更加广泛,为数据驱动的创新提供更强大的支持。
|
4月前
|
Java Python
Python学习六:面向对象编程(上)
这篇文章是关于Python面向对象编程的基础知识,包括类和对象的概念、实例方法、属性、self关键字以及魔法方法等。
28 0

热门文章

最新文章