0.说明
以下的思想方法非常有用,可以帮助你在Python开发提高开发和维护效率,所以可能的话,请仔细琢磨一下其中的代码。
之前在用Python编写一个类时,为了显示的友好性,总是需要在每个类中重载__str__或者__repr__方法,现在有了更好的方法,不需要在每个类中都这么做了,下面给出的方法非常实用。
下面使用的例子使用的Python版本都是Python3.5,但实际上在Python2.7中进行也没有任何影响。
1.正常情况下类实例的不友好显示
在Python中编写一个类时,由于没有重载__str__方法或者__repr__方法,所以在交互模式下输出一个类所创建的实例时,得到的往往是一些不太友好的显示,例如,考虑下面的一个类:>>> class Person:
... def __init__(self, name, school, major):
... self.name = name
... self.school = school
... self.major = major
现在使用该类创建一个实例:p = Person('xpleaf', 'GDUT', 'Network Engineer')
使用print()函数或者直接在交互模式下输出实例p:>>> print(p) # 如果使用Python2.7,则为print p
>>>
>>> p
可以看到,上面的输出中得不到我们想要的信息,即从输出中我们很难看出实例p的基本信息。
2.使类实例在输出中友好显示的传统方法
为了有更友好的输出显示,我们一般把上面的类重构为下面这种类型:>>> class Person:
... def __init__(self, name, school, major):
... self.name = name
... self.school = school
... self.major = major
... def __str__(self):
... return '[Person: %s, %s, %s]' % (self.name, self.school, self.major)
... def __repr__(self):
... return '[Person: %s, %s, %s]' % (self.name, self.school, self.major)
即重载了__str__方法和__repr__方法,这时再重新创建一个实例:>>> p = Person('xpleaf', 'GDUT', 'Network Engineer')
使用print()函数或者直接在交互模式下输出实例p:>>> print(p)
[Person: xpleaf, GDUT, Network Engineer]
>>>
>>> p
[Person: xpleaf, GDUT, Network Engineer]
可以看到此时的输出是友好的,从输出的结果中我们可以很容易得知实例p的信息,需要说明的是,当使用print()函数时,输出的是__str__()方法返回的字符串,而直接在交互模式下输入p时,返回的是__repr__()方法返回的字符串。
其实在很多时候,上面这样做已经可以达到友好显示实例的效果了,但是考虑一下,如果我们需要写大量的类,同时希望它们的实例的输出结果是友好,难道需要在每个类中都写类似重复的代码吗?实际上这样做是可以的,但是下面有更好的解决方法。
3.编写一个通用工具来友好显示实例
编写下面一个类,保存在classtools文件中:class AttrDisplay:
def gatherAttrs(self):
attrs = []
for key in sorted(self.__dict__):
attrs.append('%s=%s' % (key, getattr(self, key)))
return ', '.join(attrs)
def __str__(self):
return '[%s: %s]' % (self.__class__.__name__, self.gatherAttrs())
def __repr__(self):
return '[%s: %s]' % (self.__class__.__name__, self.gatherAttrs())
重构Person类,使其继承AttrDisplay类:>>> from classtools import AttrDisplay
>>>
>>> class Person(AttrDisplay):
... def __init__(self, name, school, major):
... self.name = name
... self.school = school
... self.major = major
...
创建一个实例:>>> p = Person('xpleaf', 'GDUT', 'Network Engineer')
使用print()函数或者直接在交互模式下输出实例p:>>> print(p)
[Person: major=Network Engineer, name=xpleaf, school=GDUT]
>>>
>>> p
[Person: major=Network Engineer, name=xpleaf, school=GDUT]
可以看到达到了同样的效果,但是我们并没有在Person类中重载前面两个方法,这样的工作我们把它交给了AttrDisplay类来完成。
事实上,只要我们编写的类继承了AttrDisplay属性,就可以友好的显示所创建的实例,这在需要创建大量类并且要求每个类的实例都要有友好输出时显示尤为有用。
4.在实际场景中的使用
在去年开发的Blog_mini(http://github.com/xpleaf/Blog_mini)中,由于需要定义各种类,同时因为需要在交互模式下对类进行测试,所以类中必须重载__str__方法或者__repr__方法,以使它们的输出可以更加清晰明确,但是由于当时并没有意识到这样的一种通用方法或者思想,所以每编写一个类都需要加入重复的代码,这不仅仅增加了代码量,对于维护也带来很大的不便。
所以如果可以使用这里的方法,不仅可以精简代码量,同时也便于以后进行维护,所以在今年对Blog_mini的代码进行重构时,会考虑使用这样的思想方法。
当然,如果实际中写的类不多,使用传统的方法就可以了,而且如果完全不需要在交互模式下进行类似的测试,也可以不用重载__str__和__repr__方法。
5.参考资料
《Python学习手册》 第四版 P670 “使用内省工具” 一小节