我们知道,Python面向对象编程中,在类创建完成后,一般使用__init__()方法对实例属性进行初始化。但是,在使用__init__()方法进行变量初始化时,如果使用不当,也会有一些觉察不到的“坑”。今天,我们来探讨多继承条件下,子类的__init__()方法没有显式调用父类__init__()方法后,出现的一些异常信息。
Python面向对象编程我们通过一个例子来进行说明。先来创建一个父类Person,其中初始化name、age、addr三个属性(三个属性都有默认值)。然后使用方法getInfo()获取了实例属性。然后,我们创建另一个类Student,让它继承Person类,作为Person类的子类,Student有其特定的变量grade、classes,然后重写了Student类的getInfo()方法。但是,在下面的代码中,细心的读者可能会发现,我们在子类Student中没有显式调用父类的__init__()方法。我们来看下程序运行结果。
初始化类程序运行结果如下图所示。
程序运行结果下面,我们来看一下,不修改上述代码,子类访问父类__init__()中的属性会发生什么问题?我们将子类的getInfo()方法变为这样:print(StudentInfo:Name:{}\nGender:{}\nGrade:{}.format(self.name,self.gender,self.classes))。然后,运行程序看下效果。
程序出现异常我们按照类的定义步骤,先定义了一个Person类,然后让类Student继承了Person类,按常理来说,应该是Person类中的实例变量都可以被Student类继承了,但是,我们在例子中出现的问题是,Student类中实例变量name并没有被Student类的实例所继承。问题出在哪里?这也是一些粗心的人经常会犯的一个错误,那就是没有在子类变量初始化的时候显式调用父类的__init__()方法,这样,后续代码中如果子类要使用父类的实例变量,程序就会抛出AttributeErrors异常。解决方法如下图所示。
修改子类Student中__init__()方法修改后程序正常运行,子类即可继承父类中定义的实例属性。如下图所示。
正确获取父类实例属性name值扩展至多继承的情形,我们可以通过迭代子类的__bases__属性中的内容来逐一调用父类的初始化方法。
“子类的__init__()方法如果不显式调用父类的__init__()方法,则父类__init__()方法是不会被主动调用的。”这句话大家在学习Python面向对象的编程中要牢记,不管是新手还是老鸟,都会不经意间犯上面的错误,这跟Python独特的构造方式是有关系的,因为在对象创建过程中,我们必须牢记:Obj.__init__()方法的作用只是对Obj对象中实例变量进行初始化,要创建类的实例,必须调用Obj__new__()方法,但大多数时候,我们不需要对__new__()方法进行显式调用。怎么样?是不是又是一滩雾水?对于__init__()方法和__new__()方法,我们会在后面给大家详细讲解,欢迎大家留言讨论。
转载请注明出处(百家号:Python高手养成)