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, dealercard, cards ):
self.dealercard= dealercard
self.cards= list(cards)
def str( self ):
return ", ".join( map(str, self.cards) )
def repr( self ):
return "{class.name}({dealercard!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()来转换。
在一些情况下,我们可以优化这个过程,让它更加简单。在格式化中使用位置参数可以在一定程度上简化模板字符串。
