is a :如果A是B,那么B是A的基类(父类) base class
回顾:异常,层层继承
继承
格式:
class.Student(Person)
pass
为什么要继承?继承概念引入
类里有很多重复的代码,都是人一类里的,把三者的共同特征和动作提取出来,迁移到Person类中,见下
class Person: #父类
def __init__(self):
self.name='匿名'
self.age=18
def eat(self):
print(self.name+'正在吃饭')
class Student(Person): #子类
pass
class Employee(Person):
pass
class Doctor(Person):
pass
s=Student()
s.eat()
'''
匿名正在吃饭
'''
父类为Person,子类为Student, Employee, Doctor。为无参情况
继承之后,父类的模板会给子类。调试时,s=Student()创建对象会进入Person类中的init,Student类中没有init,但父类有,执行父类的init、动作等
创建一个类,默认继承object,关系图如下
创建Student时,先找自己有没有,再一层一层往上找
Student()里有哪些东西?见下图
创建完类之后,s中有了内容
接着调用eat,Student类里没有,任进入Person类中的eat动作
总结
Student, Employee, Doctor--->都属于人类
有相同代码--->代码冗余,可读性不高
提取相同代码到Person类,Student, Employee, Doctor继承Person
继承中,父类有 init,子类也有init(Student里不再是pass,而是如下图),会出现什么情况?
能运行但会报阴影,不能运行s.eat()
报阴影原因
父类的__init__没有调用,如何调用父类的__init__?
class Person: #父类
def __init__(self):
self.name='匿名'
self.age=18
def eat(self):
print(self.name+'正在吃饭')
class Student(Person): #子类
def __init__(self):
print('---student的init')
super().__init__() #super()父类对象
s=Student()
s.eat()
'''
---student的init
匿名正在吃饭
'''
super() -> same as super(__class__, <first argument>)
以上为无参数情况
有参数情况
父类init有参,子类调用父类init时就会报阴影,因为父类init有参,所以子类调用时也要传参
class Person:
def __init__(self,name):
self.name=name
def eat(self):
print(self.name+'正在吃饭')
class Student(Person):
def __init__(self,name):
print('--->student的init')
super().__init__(name)
s=Student('tom')
s.eat()
'''
--->student的init
tom正在吃饭
'''
子类之间有各自不同的特征,如何表示?
class Person: #父类
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print(self.name+'正在吃饭')
class Student(Person): #子类
def __init__(self,name,age,class1):
super().__init__(name,age)
self.class1=class1
class Employee(Person):
def __init__(self,name,age,salary,manager):
super(Employee, self).__init__(name,age)
self.salary=salary
self.manager=manager
class Doctor(Person):
def __init__(self,name,age,patients):
super(Doctor, self).__init__(name,age)
#等同于super()__init__(name,age),多了一个判断,self属性是不是Doctor类型的
#应该用这个
self.patients=patients
s=Student('tom',18,'dian2012') #班级就是学生类独有
e=Employee('yi',23,10000,'king')
lists=['zhangsan','lisi','wangwu']
d=Doctor('lucy',24,lists)
公共部分用super叫父类帮忙,自己的部分用self.xxx。虽然继承了Person,但又各自有各自的特点
能不能定义子类自己独有的动作?
class Person: #父类
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print(self.name+'正在吃饭')
class Student(Person): #子类
def __init__(self,name,age,class1):
super().__init__(name,age)
self.class1=class1
def study(self,course):
print('{}正在学习{}课程'.format(self.name,course))
s=Student('tom',18,'dian2012')
s.eat()
s.study('python基础')
'''
tom正在吃饭
tom正在学习python基础课程
'''
子类中有和父类同名的方法,函数重写,就近原则,先找自身有没有该动作,没有的话再往父类去找
class Person: #父类
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print(self.name+'正在吃饭')
class Student(Person): #子类
def __init__(self,name,age,class1):
super().__init__(name,age)
self.class1=class1
def study(self,course):
print('{}正在学习{}课程'.format(self.name,course))
def eat(self):
super().eat() #还是能调用父类方法
print(self.name + '正在吃饭,喜欢吃西兰花')
s=Student('tom',18,'dian2012'
s.eat('西兰花')
s.study('python基础')
'''
tom正在吃饭
tom正在吃饭,喜欢吃:西兰花
tom正在学习python基础课程
'''
特点总结
1.如果类中不定义__init__,调用父类 super class的__init__
2.如果类继承父类也需要定义自己的__init__,就需要在当前类的__init__调用一下父类__init__
3.如何调用父类__init__:
super().__init__(参数)
super(类名,对象).__init__(参数)
4.如果父类有eat(),子类也定义一个eat方法,默认搜索的原则:先找当前类,再去找父类s. eat()
overwrite:重写(覆盖)
父类提供的方法不能满足子类的需求,就需要在子类中定义一个同名的方法,这种行为叫做重写
5.子类方法中也可以调用父类方法:
super().方法名(参数)
练习
'''
编写一个简单的工资管理程序,系统可以管理以下四类人:工人(worker)、销售员(salesman)、经理(manager)、销售经理(salemanager)
所有的员工都具有员工号,姓名,工资等属性,有设置姓名,获取姓名,获取员工号,计算工资等方法。
1)工人:工人具有工作小时数和时薪的属性,工资计算法方法为工作小时数*时薪。
2)销售员:具有销售额和提成比例的属性,工资计算方法为销售额*提成比例。
3)经理:具有固定月薪的属性,工资计算方法为固定月薪。
4)销售经理:工资计算方法为销售额*提成比例+固定月薪。
请根据以上要求设计合理的类,完成以下功能:
1)添加所有类型的人员
2)计算月薪
3)显示所有人工资情况
'''
class Person:
def __init__(self,no,name,salary):
self.no=no
self.name=name
self.salary=salary
#显示所有人工资情况
def __str__(self):
msg='工号:{},姓名:{},本月工资:{}'.format(self.no,self.name,self.salary)
return msg
def getSalary(self):
return self.salary
class Worker(Person):
def __init__(self,no,name,salary,hours,per_hour):
super().__init__(no,name,salary)
self.hours=hours
self.per_hour=per_hour
def getSalary(self):
money=self.hours*self.per_hour
self.salary+=money
return self.salary
class Salesman(Person):
def __init__(self, no, name, salary,salemoney,rate):
super().__init__(no, name, salary)
self.salemoney=salemoney
self.rate=rate
def getSalary(self):
money=self.salemoney*self.rate
self.salary+=money
return self.salary
#创建子类对象
w=Worker('001','yu',2000,160,30) #8h*20天
s=w.getSalary()
print('月薪是:',s)
print(w)
saler=Salesman('002','yuan',5000,5000000,0.003)
s1=saler.getSalary()
print(saler)
'''
月薪是: 6800
工号:001,姓名:yu,本月工资:6800
工号:002,姓名:yuan,本月工资:20000.0
'''
注:提到的知识点
class Person:
def __init__(self,name):
self.name=name
def eat(self):
print('eat apple')
def eat(self,food):
print('eat ',food)
p=Person('tom')
p.eat()
'''
TypeError: eat() missing 1 required positional argument: 'food'
'''
就近原则,覆盖
多重继承
class A:
def test(self):
print('--->AAA')
class B:
def test1(self):
print('--->BBB')
class C(A,B):
def test2(self):
print('--->CCC')
c=C()
c.test2()
c.test1()
'''
--->CCC
--->BBB
'''
class A:
def test(self):
print('--->AAA')
class B:
def test(self):
print('--->BBB')
class C(A,B):
def test(self):
print('--->CCC')
c=C()
c.test()
'''
--->CCC
'''
class Base:
def test(self):
print('---base---')
class A(Base):
def test(self):
print('--->AAA')
class B(Base):
def test(self):
print('--->BBB')
class C(Base):
def test(self):
print('--->CCC')
class D(A,B,C):
pass
d=D()
d.test()
import inspect
print(inspect.getmro(D))
print(D.__mro__)
'''
--->AAA
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>,
<class '__main__.C'>, <class '__main__.Base'>, <class 'object'>)
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>,
<class '__main__.C'>, <class '__main__.Base'>, <class 'object'>)
'''
def getmro(cls):
"Return tuple of base classes (including cls) in method resolution order." 按顺序搜索
return cls.__mro__
多继承的搜索顺序:经典类 新式类
经典类:广度优先 新式类:深度优先 python3为经典类
顺序应该是这样:D-C1-P1-object,然后退回到C1,C1-P2,再退回到D,D-C2