析构方法
实例被销毁的时候自动调用。网络编程用的多。
class Dog(object): def __init__(self,name): self.name = name self.__weight = 100 def sayhi(self): print('my wigth is ', self.__weight,) def __del__(self): print('del.........') d = Dog('二哈') del d #del......... print('-------------------') #-------------------
del d 并没有真正的把这个对象删除,只是把对象的引用删除了。同时垃圾回收机制把一个没有引用的空间给删除了,在删除之前执行的__del()__.
继承
使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的类称作子类 或者派生类。
被继承的类称作基类、父类或者超类。
某些oop语言中,一个子类可以继承多个基类。但是,一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承的实现有两种:实现继承和接口继承
1、实现继承是指基类的属性和方法而无需额外编码的能力
2、接口继承是指使用属性和方法的名称、但是子类必须提供实现的能力。也就是子类重构父类的方法。
使用继承时,需考虑两个类之间的关系是属于关系。
抽象类仅定义将由子类创建的一般属性和方法。
OO开发范式大致为:划分对象-》抽象类-》将类组织成为层次结构(继承和合成)->用类与实例进行设计和实现几个阶段。
简单的继承:
class Person(object): def talk(self): print('person is talking...') class BlackPerson(Person): #继承Person这个类 pass b = BlackPerson() b.talk() #person is talking...
重新父类:
class Person(object): def talk(self): print('person is talking...') class BlackPerson(Person): def talk(self): print('balabala...') b = BlackPerson() b.talk() #balabala...
重写了就调用自己的,没有重新就调用父类的。
如果父类有构造方法,子类继承父类之后也会继承父类的构造方法,如果子类重写了就不用父类的构造方法。
class Person(object): def __init__(self,name,age): self.name = name self.age = age def talk(self): print('person is talking...') class BlackPerson(Person): def talk(self): print('balabala...') b = BlackPerson() #TypeError: __init__() missing 2 required positional arguments: 'name' and 'age' b.talk()
继承了父类的构造方法,实例化的时候也必须要传递参数。
class Person(object): def __init__(self,name,age): self.name = name self.age = age def talk(self): print('person is talking...') class BlackPerson(Person): def talk(self): print('balabala...') b = BlackPerson('jim',20) b.talk() #balabala...
重写构造函数
class Person(object): def __init__(self,name,age): self.name = name self.age = age def talk(self): print('person is talking...') class BlackPerson(Person): def __init__(self,name): self.name = name def talk(self): print('balabala...') b = BlackPerson('jim') b.talk() #balabala...
子类重写父类构造,那么就会调用自己的构造,但是我又需要父类的构造函数,有些功能相同的代码不想重写。这个时候可以使用先继承在重构。
先继承在重构
class Person(object): def __init__(self,name,age): self.name = name self.age = age def talk(self): print('person is talking...') class WhitePerson(Person): pass class BlackPerson(Person): def __init__(self,name,age,strength): #先继承,在重构 子类重构父类方法,实例化的时候参数都传到子类,self就是b Person.__init__(self,name,age) #这里调用父类的构造方法 这里的self,name,age 都来自与子类 print(self.name,self.age) # jim 20 def talk(self): print('balabala...') b = BlackPerson('jim','20','500') b.talk()
子类的实例传到父类,让父类赋值。
子类调用父类的方法
class Person(object): def __init__(self,name,age): self.name = name self.age = age def talk(self): print('person is talking...') class BlackPerson(Person): def __init__(self,name,age,strength): #先继承,在重构 子类重构父类方法,实例化的时候参数都传到子类,self就是b Person.__init__(self,name,age) #这里调用父类的构造方法 这里的self,name,age 都来自与子类 def talk(self): Person.talk(self) print('balabala...') b = BlackPerson('jim','20','500') b.talk() #person is talking... #balabala...
小练习:
算下学校老师和学生的注册人数,并打印用户信息。
class SchoolMember(object): '''学校成员基类''' member = 0 # 计数器 def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex self.enroll() def enroll(self): '''注册''' print('just enerolled a new school member [%s]'% self.name) SchoolMember.member += 1 #实例本身有就调用本身的,没有就调用全局的 def tell(self): print('----%s info-----'% self.name) for k,v in self.__dict__.items(): print(' ',k,v) def __del__(self): print('%s退学了..'%self.name) SchoolMember.member -= 1 class Teacher(SchoolMember): '''讲师类''' def __init__(self,name,age,sex,salary,course): SchoolMember.__init__(self,name,age,sex) self.salary = salary self.course = course def teaching(self): print('Teacher [%s] is teaching [%s]'%(self.naem,self.course)) class Student(SchoolMember): '''学生类''' def __init__(self,name,age,sex,course,tuition): SchoolMember.__init__(self,name,age,sex) self.course = course self.tuition = tuition self.amount = 0 def pay_tuition(self,amount): print('student [%s] has just paied [%s]'%(self.name,amount)) self.amount += amount t1 = Teacher('jim',20,'M',5000,'python') s1 = Student('Lily',22,'W','python',300000) s2 = Student('Lilei',23,'M','python',200000) t1.tell() s1.tell() s2.tell() print(SchoolMember.member) del s2 print(SchoolMember.member)
just enerolled a new school member [jim] just enerolled a new school member [Lily] just enerolled a new school member [Lilei] ----jim info----- age 20 course python sex M salary 5000 name jim ----Lily info----- age 22 course python sex W tuition 300000 amount 0 name Lily ----Lilei info----- age 23 course python sex M tuition 200000 amount 0 name Lilei 3 Lilei退学了.. 2 Lily退学了.. jim退学了..
多继承
class SchoolMember(object): '''学校成员基类''' member = 0 # 计数器 def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex self.enroll() def enroll(self): '''注册''' print('just enerolled a new school member [%s]'% self.name) SchoolMember.member += 1 #实例本身有就调用本身的,没有就调用全局的 def tell(self): print('----%s info-----'% self.name) for k,v in self.__dict__.items(): print(' ',k,v) def __del__(self): print('%s退学了..'%self.name) SchoolMember.member -= 1 class School(object): def open_branch(self,addr): print('openning a new branch in ',addr) class Teacher(SchoolMember,School): #多继承 '''讲师类''' def __init__(self,name,age,sex,salary,course): # SchoolMember.__init__(self,name,age,sex) super(Teacher,self).__init__(name,age,sex) self.salary = salary self.course = course def teaching(self): print('Teacher [%s] is teaching [%s]'%(self.naem,self.course)) class Student(SchoolMember): '''学生类''' def __init__(self,name,age,sex,course,tuition): SchoolMember.__init__(self,name,age,sex) self.course = course self.tuition = tuition self.amount = 0 def pay_tuition(self,amount): print('student [%s] has just paied [%s]'%(self.name,amount)) self.amount += amount t1 = Teacher('jim',20,'M',5000,'python') t1.open_branch('SZ') print(SchoolMember.member)
执行结果
just enerolled a new school member [jim] openning a new branch in SZ 1 jim退学了..
新式类VS经典类
接着上面的例子练习:
修改Teacher类中调用父类构造的方法。其它代码不修改
# SchoolMember.__init__(self,name,age,sex) #经典类的写法 super(Teacher,self).__init__(name,age,sex) #新式类的写法
-------------------------------------------------
t1 = Teacher('jim',20,'M',5000,'python') #学生的不调用
t1.tell()
print(SchoolMember.member)
执行结果:
just enerolled a new school member [jim] ----jim info----- course python name jim salary 5000 age 20 sex M 1 jim退学了..
可以看到效果和之前的一样 .super这种写法是一种新式类的写法。
新式类和经典类的区别
1.语法
class Person(object): #新式类
super class Person: #经典类
ParentClass.__init__
2 多继承时的继承顺序
看个小例子:
四个类继承顺序如下:
新式类写法
class A(object): def __init__(self): self.n = 'A' class B(A): def __init__(self): self.n = 'B' class C(A): def __init__(self): self.n = 'C' class D(B,C): def __init__(self): self.n = 'D' d = D() print(d.n) #D
d把所有的父类方法重新了,打印肯定是它自己的
如果D没有构造函数,那么这里会打印谁的?
class A(object): def __init__(self): self.n = 'A' class B(A): def __init__(self): self.n = 'B' class C(A): def __init__(self): self.n = 'C' class D(B,C): pass ''' def __init__(self): self.n = 'D' ''' d = D() print(d.n) #B
继承顺序从左往右。所有先继承B
如果B没有构造函数,所以会继承C的,如果C也没有的话就会继承A的,这种叫广度查找,会把一个层级的查找完
class A(object): def __init__(self): self.n = 'A' class B(A): pass class C(A): def __init__(self): self.n = 'C' class D(B,C): pass d = D() print(d.n) #C
经典类写法
class A: def __init__(self): self.n = 'A' class B(A): def __init__(self): self.n = 'B' class C(A): def __init__(self): self.n = 'C' class D(B,C): pass d = D() print(d.n) #B
同样去掉B的构造函数
class A: def __init__(self): self.n = 'A' class B(A): pass class C(A): def __init__(self): self.n = 'C' class D(B,C): pass d = D() print(d.n)#C
去掉C的构造函数
class A: def __init__(self): self.n = 'A' class B(A): pass class C(A): pass class D(B,C): pass d = D() print(d.n)#A
并没有什么区别,继承顺序也是一样的。
在Python2.7下,如果B没有构造函数,会直接找A,并不会找C,r如果A没有才会找C,这种叫深度查找。