《Python面向对象编程指南》——2.2 __format__()方法

简介:

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

2.2 __format__()方法

string.format()和内置的format()函数都使用了__format__()方法。它们都是为了获得给定对象的一个符合要求的字符串表示。

下面是给__format__()传参的两种方式。

  • someobject.__format__(""):当应用程序中出现format(someobject)或者"{0}".format(someobject)时,会默认以这种方式调用__format__()。在这些情况下,会传递一个空字符串,__format__()的返回值会以默认格式表示。
  • someobject.__format__(specification):当应用程序中出现format (someobject, specification)或者"{0:specification}".format (someobject)"时,会默认以这种方式调用__format__()。

注意,"{0!r}".format()和"{0!s}".format()并不会调用__format__()方法。它们会直接调用__repr__()或者__str__()。

当specification是""时,一种合理的返回值是return str(self),这为各种对象的字符串表示形式提供了明确的一致性。

在一个格式化字符串中,":"之后的文本都属于格式规范。当我们写"{0:06.4f}"时,06.4f是应用在项目0上的格式规范。

Python标准库的6.1.3.1节定义了一个复杂的数值规范,它是一个包括9个部分的字符串。这就是格式规范的基本语法,它的语法如下。

[[fill]align][sign][#][0][width][,][.precision][type]

这些规范的正则表示如下。

re.compile(
r"(?P<fill_align>.?[\<\>=\^])?"
"(?P<sign>[-+ ])?"
"(?P<alt>#)?"
"(?P<padding>0)?"
"(?P<width>\d*)"
"(?P<comma>,)?"
"(?P<precision>\.\d*)?"
"(?P<type>[bcdeEfFgGnosxX%])?" )

这个正则表达式将规范分解为8个部分。第1部分同时包括了原本规范中的fill和alignment字段。我们可以利用它们定义我们的类中的数值类型的格式。

但是,Python格式规范的语法有可能不能很好地应用到我们之前定义的类上。所以,我们可能需要定义我们自己的规范化语法,并且使用我们自己的__format__()方法来处理它。如果我们定义的是数值类型,那么我们应该使用Python中内建的语法。但是,对于其他类型,没有理由坚持使用预定义的语法。

例如,下面是我们自定义的一个微型语言,用%r来表示rank,用%s来表示suit,用%代替%%,所有其他的文本保持不变。

我们可以用下面的格式化方法扩展Card类。

def __format__( self, format_spec ):
   if format_spec == "":
     return str(self)
   rs= format_spec.replace("%r",self.rank).replace("%s",self.suit)
   rs= rs.replace("%%","%")
   return rs

方法签名中,需要一个format_spec作为格式规范参数。如果没有提供这个参数,那么就会使用str()函数来返回结果。如果提供了格式规范参数,就会用rank、suit和%字符替换规范中对应的部分,来生成最后的结果。

这允许我们使用下面的方法来格式化牌。

print( "Dealer Has {0:%r of %s}".format( hand.dealer_card) )

其中,("%r of %s")作为格式化参数传入__format__()方法。通过这种方式,我们能够为描述自定义对象提供统一的接口。

或者,我们可以用下面的方法:

default_format= "some specification"
def __str__( self ):
   return self.__format__( self.default_format )
def __format__( self, format_spec ):
   if format_spec == "": format_spec = self.default_format
   # process the format specification.

这种方法的优点是把所有与字符串表示相关的逻辑放在__format__()方法中,而不是分别写在__format__()和__str__()里。但是,这样做有一个缺点,因为并非每次都需要实现__format__()方法,但是我们总是需要实现__str__()。

2.2.1 内嵌格式规范

string.format()方法可以处理{}中内嵌的实例,替换其中的关键字,生成新的格式规范。这种替换是为了生成最后传入__format__()中的格式化字符串。通过使用这种内嵌的替换,我们可以使用一种更加简单的带参数的更加通用的格式规范,而不是使用相对复杂的数值格式。

下面是使用内嵌格式规范的一个例子,它让format参数中的width更容易改变:

width=6
for hand,count in statistics.items():
   print( "{hand}{count:{width}d}".format(hand=hand,count=count,width= width) )

我们定义了一个通用的格式,"{hand}{count:{width}d}",它需要一个width参数,才算是一个正确的格式规范。

通过width=参数提供的值会被用来替换{width}。替换完成后,完整的格式化字符串会作为__format__()方法的参数使用。

2.2.2 集合和委托格式规范

当格式化一个包含集合的对象时,我们有两个难题:如何格式化整个对象和如何格式化集合中的对象。以Hand为例,其中包含了Cards类的集合。我们会更希望可以将Hand中一部分格式化的逻辑委托给Card实例完成。

下面是Hand中的format()方法。

def __format__( self, format_specification ):
   if format_specification == "":
     return str(self)
   return ", ".join( "{0:{fs}}".format(c, fs=format_specification)
     for c in self.cards )

Hand集合中的每个Card实例都会使用format_specification参数。对于每一个Card对象,都会使用内嵌格式规范的方法,用format_specification创建基于"{0:{fs}}"的格式。通过这样的方法,一个Hand对象,player_hand,可以以下面的方法格式化:

"Player: {hand:%r%s}".format(hand=player_hand)

这会将%r%s格式规范应用在Hand对象中的每个Card实例上。

相关文章
|
5月前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
482 1
|
6月前
|
机器学习/深度学习 数据采集 数据挖掘
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
237 2
|
6月前
|
调度 Python
微电网两阶段鲁棒优化经济调度方法(Python代码实现)
微电网两阶段鲁棒优化经济调度方法(Python代码实现)
181 0
|
6月前
|
传感器 大数据 API
Python数字限制在指定范围内:方法与实践
在Python编程中,限制数字范围是常见需求,如游戏属性控制、金融计算和数据过滤等场景。本文介绍了五种主流方法:基础条件判断、数学运算、装饰器模式、类封装及NumPy数组处理,分别适用于不同复杂度和性能要求的场景。每种方法均有示例代码和适用情况说明,帮助开发者根据实际需求选择最优方案。
311 0
|
6月前
|
Python
Python字符串center()方法详解 - 实现字符串居中对齐的完整指南
Python的`center()`方法用于将字符串居中,并通过指定宽度和填充字符美化输出格式,常用于文本对齐、标题及表格设计。
|
5月前
|
人工智能 数据安全/隐私保护 异构计算
桌面版exe安装和Python命令行安装2种方法详细讲解图片去水印AI源码私有化部署Lama-Cleaner安装使用方法-优雅草卓伊凡
桌面版exe安装和Python命令行安装2种方法详细讲解图片去水印AI源码私有化部署Lama-Cleaner安装使用方法-优雅草卓伊凡
789 8
桌面版exe安装和Python命令行安装2种方法详细讲解图片去水印AI源码私有化部署Lama-Cleaner安装使用方法-优雅草卓伊凡
|
6月前
|
机器学习/深度学习 数据采集 算法
【CNN-BiLSTM-attention】基于高斯混合模型聚类的风电场短期功率预测方法(Python&matlab代码实现)
【CNN-BiLSTM-attention】基于高斯混合模型聚类的风电场短期功率预测方法(Python&matlab代码实现)
375 4
|
5月前
|
算法 调度 决策智能
【两阶段鲁棒优化】利用列-约束生成方法求解两阶段鲁棒优化问题(Python代码实现)
【两阶段鲁棒优化】利用列-约束生成方法求解两阶段鲁棒优化问题(Python代码实现)
158 0
|
6月前
|
机器学习/深度学习 数据采集 TensorFlow
基于CNN-GRU-Attention混合神经网络的负荷预测方法(Python代码实现)
基于CNN-GRU-Attention混合神经网络的负荷预测方法(Python代码实现)
359 0
|
7月前
|
数据管理 开发工具 索引
在Python中借助Everything工具实现高效文件搜索的方法
使用上述方法,你就能在Python中利用Everything的强大搜索能力实现快速的文件搜索,这对于需要在大量文件中进行快速查找的场景尤其有用。此外,利用Python脚本可以灵活地将这一功能集成到更复杂的应用程序中,增强了自动化处理和数据管理的能力。
625 0

推荐镜像

更多