9.4 classmethod与staticmethod
Python 教程没有提到 classmethod 装饰器,也没有提到 staticmethod。学过 Java 面向对象编程的人可能觉得奇怪,为什么 Python 提供两个这样的装饰器,而不是只提供一个?
先来看 classmethod。示例 9-3 展示了它的用法:定义操作类,而不是操作实例的方法。classmethod 改变了调用方法的方式,因此类方法 的第一个参数是类本身,而不是实例。
class Demo:
@classmethod
def class_func(*args):
return args
@staticmethod
def static_func(*args):
return args
# class_func 返回全部位置参数。
# 不管怎样调用 Demo.class_func,它的第一个参数始终是 Demo 类本身。
print(Demo.class_func()) # (<class '__main__.Demo'>,)
print(Demo.class_func('spam')) # (<class '__main__.Demo'>, 'spam')
# static_func 返回全部位置参数。
# Demo.static_func 的行为与普通的函数相似。
print(Demo.static_func()) # ()
print(Demo.static_func('spam')) # ('spam',)
classmethod 装饰器非常有用,但是我从未见过不得不用 staticmethod 的情况。如果想定义不需要与类交互的函数,那么在模块中定义就好了。有时,函数虽然从不处理类,但是函数的功能与类紧密相关,因此想把它放在近处。
9.5 格式化显示
内置的 format() 函数和 str.format() 方法把各个类型的格式化方式 委托给相应的 .__format__(format_spec) 方法。format_spec 是格式说明符,它是:
- format(my_obj, format_spec) 的第二个参数;
- 或者 str.format() 方法的格式字符串,{} 里代换字段中冒号后面的部分;
例如:
# BRL到USD的货币兑换比价 >>> brl
brl = 1 / 2.43 # 0.4115226337448559
# 1. 格式说明符是 '0.4f'
print(format(brl, '0.4f')) # '0.4115'
# 2. 格式说明符是 '0.2f'。
# 代换字段中的 'rate' 子串是字段名称,与格式说明符无关,但是它决定把 .format() 的哪个参数传给代换字段。
print('1 BRL = {rate:0.2f} USD'.format(rate=brl)) # '1 BRL = 0.41 USD'
示例中第 2 条标注指出了一个重要知识点:'{0.mass:5.3e}' 这样的格式字符串其实包含两部分,冒号左边的 '0.mass' 在代换字段句法中是字段名,冒号后面的 '5.3e' 是格式说明符,这种格式说明符使用的表示法叫格式规范微语言。
格式规范微语言为一些内置类型提供了专用的表示代码。比如,b 和 x 分别表示二进制和十六进制的 int 类型,f 表示小数形式的 float 类 型,而 % 表示百分数形式:
# 二进制
print(format(42, 'b')) # '101010'
# 十六进制
print(format(42, 'x')) # '2a'
# 百分比表达方式,.3% 代表保留 3 位小数
print(format(2 / 3, '.3%')) # '66.667%'
格式规范微语言是可扩展的,因为各个类可以自行决定如何解释 format_spec 参数。例如, datetime 模块中的类,它们的 __format__ 方法使用的格式代码与 strftime() 函数一样。下面是内置的 format() 函数和 str.format() 方法的几个示例:
from datetime import datetime
now = datetime.now()
print(now) # 2020-08-06 10:39:39.304216
print(format(now, '%H:%M:%S')) # 10:39:39
print("It's now {:%I:%M %p}".format(now)) # It's now 10:39 AM