构造方法也是函数,但是它调用的时间是确定的,当一个对象被创建之后,会立即调用构造方法。
原来我在写objective-c和C#时都会写构造方法,用来初始化类中属性。而且需要显示的调用。
Python中有一类魔法方法(特殊方法),初始化用到是init。
class Person:
def __init__(self):
self.name = "nzh"
self.age = 25
p1 = Person()
print("p1的姓名:{0},年龄:{1}".format(p1.name, p1.age))
在init函数中,我们设定了两个属性,name和age。并且直接赋值。
在调用Person()函数时,它会隐式调用init()函数,然后Person类的对象中的属性就被设置了。
init()函数中默认会传递一个self的参数,self代表的是对象自己,那么生成p1对象时调用的Person()函数时,这个self就代表了p1,self会对当前对象进行绑定。
上面的例子我们是把属性值都定死了,这不够灵活。如果想让自定义属性的值,就需要给init()函数传递参数。
# 构造一个用户信息
class User:
def __init__(self, name, age):
self.name = name
self.age = age
user1 = User("nzh", 25)
print("user1用户的名字:{0},年龄:{1}".format(user1.name, user1.age))
Python中有一个魔法方法叫del,相当于析构函数,它的作用是在被垃圾回收之前调用,但是发生的时间不可预知,应该尽力避免使用。
构造方法在继承中的使用
现在有两个类,A和B。B是A的子类。
A中定义了一个hello方法,B中没有定义任何内容,当B的对象调用hello方法时,同样可以调用。因为hello方法是从父类A中继承过来的。
这里面跟构造函数有很大关系,因为B的构造方法调用了A的构造方法,如果不是这样,B中就不能调用hello方法。
那么如何调用父类的构造方法?有两种方式。
调用未绑定的超类构造方法
在Python3.0之前会用到的方法,现在更流行用super函数,稍后说super,先说未绑定。
class Bird():
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry == True:
print("吃点东西...")
self.hungry = False
else:
print("我不饿,谢谢")
class SongBird(Bird):
def __init__(self):
self.sound = "this is a song"
def sing(self):
print(self.sound)
s = SongBird()
s.sing()
s.eat()
这里SongBird类的对象不能调用eat方法,就是因为在SongBird初始化的时候没有调用超类的构造方法,可以修改SongBird的初始化函数init()
class SongBird(Bird):
def __init__(self):
Bird.__init__(self)
self.sound = "this is a song"
def sing(self):
print(self.sound)
加了一句Bird.init(self)就能调用了Bird类中的eat方法了?背后发生了一些事情。
在调用一个实例的方法时,该方法的self参数会被自动绑定到实例上(这叫绑定方法)。如果只是调用Bird.init(),而没有给它传递self参数,那么Bird也不知道绑定了哪个实例,而且会引发一个TypeError错误。
正如上图所示,错误信息显示init()方法少了一个必要的参数self。
如果直接调用Bird类的Bird.init呢?(看起来像是一个属性,而非方法)
同样可以看到,提示没有hungry属性,没有提供self参数,实例就不会被绑定,这样就可以随便提供self参数。
例子中是吧SongBird的self传给了Bird的init函数(不知道这么理解对不对),这种方法就是未绑定方法(unbound)
使用super函数
首先得知道super函数只能在新式类中使用,如果你使用过老版本的python那么就不行了。至少是2.2以后,因为super是2.2新加入的特性。
修改SongBird类:
class SongBird(Bird):
def __init__(self):
super(SongBird, self).__init__()
self.sound = "this is a song"
def sing(self):
print(self.sound)
为什么一个super就解决了这些问题呢?其实super函数很只能,不管你的这个类继承了多少层超类,它只需要使用一次super函数就可以调用超类中的方法,前提是这些超类中都要使用super函数。
super函数返回的是一个super对象,它负责对调用的方法进行解析,以至于我们可以成功调用超类中的方法。
有多层继承关系时,子类从下至上逐层寻找,比如D是C的子类,C是B的子类,B是A的子类。
那么继承关系就是这样的A->B->C->D。
D中先到C中找,如果C中没有该方法,再去B中找,最后再去A中找。找不到会报错,异常类型为AttributeError。