Python __init__ VS 构造方法

很多书和资料都把__init__视为python class实例的构造器,如果你是学习静态语言比如java/Csharp或者c++出身的,你会发现__init__与静态语言的构造器有很大出入,换句话说,如果你真的以为__init__就是constructor,那你可能会被下面的诡异现象逼疯,按照诡异程度,依次为:

 

  • 1.构造器执行时,实例已经被构造好了???
  • 2.子类实例化时,父类的构造器可以被不调用???
  • 3.构造器可以继承???

 

一条条的说:

1. 这个是首先被注意到的,self是什么鬼?:

class Base:

    def __init__(self, a, b=1):

        print("Base __init__")

 

都说self是实例方法被调用时,解释器自动传入指向当前实例的指针。那么,__init__如果是构造器,就是说构造器还未执行,对象就已经存在了?

 

2. 静态语言学得不错同学,会认为这段代码是错的(事实确实是错的)

class Base:

    def __init__(self, a, b=1):

        self.aa = 1

        self.bb = b

        print("Base __init__")





class Child(Base):

    # def __init__(self):

    #     print("Child __init__")

    pass



c = Child()

因为按照java的观念,基类的构造函数无参构造器,子类构造器会在第一行自动调用,并且若子类没有构造方法,编译器会默认添加无参构造器,并自动调用基类构造器;如果基类只有有参构造器,那子类就必须显示调用基类的构造方法。

好,如果按这种思路,那么把注释解开之后,代码应该还是错的,因为Child并没有显示调用Base的__init__方法。

但实际运行一下,你会百思不得其解:代码可以执行,而且只有Child的__init__被执行了,难道Base实例没有被初始化?WTF

 

3. 这是最不能接受的,在java中,静态或者private属性/方法,以及构造器都是不能继承的。再说你把父类的构造器继承给子类也说不过去啊,但请看如下代码:

class Base:

    def __init__(self, a, b=1):

        self.aa = 1

        self.bb = b

        print("Base __init__")





class Child(Base):

    pass



c = Child(1)

print(c.aa)

 

输出是:

Base __init__

1

 

然后,打印一下方法的地址:

print(id(Base.__init__))

print(id(Child.__init__))

print(id(Base.__new__))

print(id(Child.__new__))

结果:

2198486489696

2198486489696

2198486489832

2198486489832

 

确实Child继承了Base的__init__

到这一步,如果你还把__init__当成构造器,那么之后脑袋会一盆浆糊,python八成是学不好了。

其实,__init__只是一个普通的初始化函数,它可以被继承,也可以被重载,唯一特殊的地方在于实例被构造的最后一个阶段,__init__会被调用,对构造好的实例执行一些初始化操作。

这样想之后,心里是不是舒坦一点?实际上,当执行:c = Child(1)

实际Child()才是构造方法,这个构造方法做了两件事:

  • 调用allocator分配内存:__new__方法,生成实例
  • 调用initializer,__init__,为实例做一些初始化工作

 

所以,解释以上三点:

1.构造器执行时,实例已经被构造好了???

当然了,因为__init__只是一个initializer。

 

2.子类实例化时,父类的构造器可以被不调用???

如果子类重写了父类的__init__,那父类的__init__就不被调用了,注意,此时如果子类的__init__方法中没有执行super(child,self).__init__或者base.__init__,那么当前实例就缺少了一些父类初始化的工作,可能会导致属性或者功能的缺失。

 

3.构造器可以继承???

__init__只是一个普通方法,可以被继承,也可以被重写。所以当子类也有一个构造方法时,会重写(override)父类的__init__

你可能感兴趣的:(Python3,python,__init__,构造方法,语法,java)