本节书摘来自异步社区《Python面向对象编程指南》一书中的第1章,第1.2节,作者[美]Steven F. Lott, 张心韬 兰亮 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。
1.2 基类中的__init__()方法
对象的生命周期主要包括了创建、初始化和销毁。后面章节会详细讨论对象的创建和销毁,本章专注于对象的初始化。
object作为所有类的基类,已经为__init__()方法提供了默认实现,一般情况下不需要重写这个函数。如果没有对它进行重写,那么在创建对象时将不会产生其他变量的实例。在某些情况下,这种默认行为是可以接受的。
对于继承自object的子类,总可以对它的属性进行扩展。例如,对于下面这个类,实例化就不对函数(area)所需要的变量(width和length)进行初始化。
class Rectangle:
def area( self ):
return self.length * self.width
Rectangle类的area函数在返回值时使用了两个属性,可并没有在任何地方对其赋值。在Python中,这种看似奇怪的调用尚未赋值属性的操作却是合法的。
下面这段代码演示如何使用刚定义的Rectangle类。
>>> r= Rectangle()
>>> r.length, r.width = 13, 8
>>>r.area()
104
虽然这种延迟赋值的实现方式在Python中是合法的,但是却给调用者带来了潜在的困惑,因此要尽量避免这样的用法。
然而,这样的设计看似又提供了灵活性,意味着在__init__()方法被调用时不必为所有的属性赋值。这看似是不错的选择,一个可选属性即可以看作是某子类中的成员,且无须对这个子类进行显式地定义就可以完成对原生机制的扩展。然而这种多态机制不但给程序带来了隐藏的不确定性,也会相应产生很多令人费解的if语句。
因此,延迟初始化属性的设计在某种情形下可能会有用,可是这样也可能会导致非常糟糕的设计。
在Zen of python poem一书中曾提出过这样的建议:
“显式而非隐式”。
对于每个__init__()方法,都应当显式地指定要初始化的变量。