8.4 构造函数

对于一个新定义的类,我们之所以能够用类似于这样的语句:  stu=Student() 来声明一个新的对象,其实是调用了一个函数,这个函数叫做构造函数。 什么是构造函数呢,有什么作用呢?
构造函数的作用是给新创建的对象分配内存,初始化属性的值。对于分配内存,我们不用做什么,编译器已经做好了,我们要自己写的是后面的那个:初始化属性。事实上,你就算是一个这样的类,里面什么都没有:
class Chapter:pass
即使这个类貌似什么“内容”都没有 ,编译器也自动给你添加了一个没有参数的构造函数,这个自动添加的构造函数,使得你可以创建对象,例如这样:
c = Chapter()
虽然编译器会提供一个缺省构造函数,但我们通常需要手动写,__init__就是构造函数首先自动调用的函数(注意是"两个下划线+init+两个下划线"),我们在此章节把init和构造函数当做同义词:
class Chapter:
    def __init__(self):
        print("构造函数被调用")
        self.id = 1000
        self.code = ""
        self.name = ""
        self.content = ""
        self.parentCode = ""
c = Chapter()
c2 = Chapter()
c1 = Chapter()
c4 = Chapter()
print(c.id)
1. init函数没有返回值,但是构造函数把生成的对象返回
2. 如果没有写构造函数,编译器会提供一个无参数构造函数
3. init函数只能有一个
4. 通常把属性的定义直接写在构造函数里

这里也展示了python类通常的写法:在构造函数里定义属性。
代码执行的时候,“构造函数被调用”会打出4次,因为声明了4个Chapter对象,最终打印的1000是因为c的id值在构造函数中初始化为1000。

python类的构造函数只能有一个。构造函数的参数可以自己定义。
假设id值是任何对象都必须要有的值,它很重要。那么我们可以写一个这样的构造函数:
class Chapter:
    def __init__(self,id):
        print("构造函数被调用")
        self.id = id
        self.code = ""
        self.name = ""
        self.content = ""
        self.parentCode = ""
c = Chapter(8898)
print(c.id)
c2 = Chapter() #这行语法错误,因为没有无参数的构造函数
如果类里面没有任何构造函数,编译器会自动生成一个无参数的构造函数;如果类里面已经有构造函数,那么编译器不会生成无参数的构造函数。(你无我生成,你有我不管)。所以上面最后一行的代码错误了,因为已经没有无参数的构造函数,系统也不再提供。

这个构造函数需要一个参数,用来设置id值。那么新生成一个对象的时候,就可以这样调用了,Chapter对象c被创建,同时c的id属性赋值为8898,同时还可以生成一个新的对象c2,但什么属性都不设置,但这里会出语法错误,因为c2的构造函数参数数量不对。如果需要c2对象也生效,那么可以把id设置成缺省参数(函数参数默认值):
class Chapter:
    def __init__(self,id=1000):
        print("构造函数被调用")
        self.id = id
        self.code = ""
        self.name = ""
        self.content = ""
        self.parentCode = ""
c = Chapter(8898)
print(c.id)
c2 = Chapter() 
print(c2.id)

如果有两个以上的参数,并且有缺省值,那么看下面的例子:
class Chapter:
    def __init__(self,id=1000,code=124587):
        print("构造函数被调用")
        self.id = id
        self.code = code
        self.name = ""
        self.content = ""
        self.parentCode = ""
# 不指定任何参数,那么所有参数使用默认
c = Chapter()
print(c.id,c.code)
# 指定参数为code,那么id值使用默认的1000
c1=Chapter(code=1123)
print(c1.id,c1.code)
#不指定参数名,那么就从最左边参数开始匹配,1123就是参数id
c2=Chapter(1123)
print(c2.id,c2.code)
#不指定参数名,那么就从最左边参数开始匹配,1123就是参数id,886就是code
c3=Chapter(1123,886)
print(c3.id,c3.code)