昨日回顾
类的加载顺序
- 类内部的代码什么时候执行?
- 除了方法里面的代码
- 其余的所有内容都是在执行这个文件的时候就从上到下依次执行的
- 不需要调用
- 如果有同名的方法、属性,总是写在后面的会生
class A:
wahaha = 'adGa'
def wahaha(self):
pass
a = A()
print(a.wahaha) # 就是后加载进来的方法覆盖了之前加载的属性
类和对象的命名空间
- 类的命名空间 是在定义类的阶段被加载进来的:
- 静态变量、类变量 —— 直接定义在类中的变量
- 动态变量、方法 —— 定义在类中的函数
- 魔术方法、双下方法
- 内置的方法 :__init__
- 内置的变量 : __dict__
- 对象的命名空间 实例化的时候创建出来的
- 类指针、类对象指针 执行init之前就已经在了
- 对象的属性 是在执行init以及之后被添加的
class Student:
'''这里是对学生类的功能描述'''
print('123')
print(Student.__dict__)
print(Student.__doc__)
print(Student.__class__)
a = 3
b = 2
def fun():
a = 4
def inner():pass
class A:
a = 1
def func(self):
pass
print(a)
print(A.a)
class A: # parameters形参 arguments实参
pass
a = A()
#init这个东西你在定义一个类的时候
#假如没有什么属性是你想添加给对象的,你也可以不写init
class Student:
def __init__(self,name,age,course):
self.name = name
self.age = age
self.course = course # self.course = python
class Course:
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period
python = Course('python',20000,'6 months') # python是一个课程对象
print(python.name)
ju = Student('菊哥',30,python)
#一个类的属性 是一个对象
Student类的course属性 是python对象
#学生的课程属性 和 python对象组合了
#可以通过学生 找到python 可以通过python找到python课程的名字、价格、周期
self.course = python
self.course.name = python.name
print(ju.course.name)
print(ju.course.price)
扩展
ju.name # 字符串
ju.name.strip()
ju是Student类的对象
ju.name是一个字符串 是str的一个对象
Student类 和 str类 组合
ju.age
ju是Student类的对象
ju.age是int的一个对象
Student类 和 int类 组合
今日内容
- 面向对象三大特性
- 继承 *****
- 多态 *
- 封装 *****
- 继承 *****
- 单继承 可以有效的帮我们提高代码的重用性
- 我们写代码的时候
- 多继承
- 规范复杂的功能与功能之间的关系
- 工作原理能够帮助你去看源码
- 面试重点
单继承
class A(类的名字B):
pass
##A就变成了B的儿子
# B是 父类、基类、超类
# A是 子类、派生类
class Parent:
pass
class Son(Parent):
pass
print(Son.__bases__)
##多继承
class Parent1:
pass
class Parent2:
pass
class Son(Parent1,Parent2):
pass
print(Son.__bases__)
为什么要继承
- 两个类
- 猫 :
- 属性 :名字,品种,眼睛的颜色
- 动作 :吃、喝、爬树、抓老鼠
- 狗
class Cat(object):
def __init__(self,name,kind,eyes_color):
self.name = name
self.kind = kind
self.eyes_color = eyes_color
def eat(self,food):
print('%s eat %s'%(self.name,food))
def drink(self):
print('%s drink water'%(self.name))
def climb(self):
print('%s climb tree'%(self.name))
def catch(self):
print('%s catch mouse'%(self.name))
class Dog(object):
def __init__(self,name,kind):
self.name = name
self.kind = kind
def eat(self,food):
print('%s eat %s'%(self.name,food))
def drink(self):
print('%s drink water'%(self.name))
def catch(self):
print('%s catch mouse'%(self.name))
def chai(self):
print('%s cha'%(self.name))
class Animal(object):
def __init__(self,name,kind):
self.name = name
self.kind = kind
def eat(self,food):
print('%s eat %s'%(self.name,food))
class Cat(Animal):pass
class Dog(Animal):pass
hua = Cat('小花','橘猫')
print(hua)
print(hua.name)
print(hua.kind)
hua.eat('小鱼干')
hei = Dog('小黑','中华田园犬')
print(hei.name)
print(hei.kind)
hei.eat('单身狗粮')
class Animal(object):
def __init__(self,name,kind):
self.name = name
self.kind = kind
def eat(self,food):
print('%s eat %s'%(self.name,food))
class Cat(Animal):
def __init__(self,name,kind,eyes_color):
self.eyes_color = eyes_color
Animal.__init__(self,name,kind) # 在子类和父类有同名方法的时候,默认只执行子类的方法
# 如果想要执行父类的方法,可以在子类的方法中再 指名道姓 的调用父类的方法
class Dog(Animal):pass
hua = Cat('小花','橘猫','蓝色')
print(hua.__dict__)
当Cat自己拥有__init__的时候,就不再调用父类的了
class Animal:
def __init__(self,name,kind):
self.name = name
self.kind = kind
def eat(self,food):
print('%s eat %s'%(self.name,food))
class Cat(Animal):
def __init__(self,name,kind,eyes_color):
self.eyes_color = eyes_color
# super(Cat,self).__init__(name,kind)
# super().__init__(name,kind) # 相当于执行父类的init方法
# Animal.__init(self,name,kind)
class Dog(Animal):pass
hua = Cat('小花','橘猫','蓝色')
print(hua.__dict__)
class Animal(object):
def __init__(self,name,kind):
self.name = name
self.kind = kind
def eat(self,food):
print('%s eat %s'%(self.name,food))
def drink(self):
print('%s drink water'%(self.name))
def catch(self):
print('%s catch mouse'%(self.name))
class Cat(Animal):
def __init__(self,name,kind,eyes_color):
self.eyes_color = eyes_color # 派生属性
# super(Cat,self).__init__(name,kind)
super().__init__(name,kind) # 相当于执行父类的init方法
# Animal.__init(self,name,kind)
def climb(self): # 派生方法
print('%s climb tree'%self.name)
class Dog(Animal):
def chai(self):
print('%s cha'%(self.name))
hua = Cat('小花','橘猫','蓝色')
hua.eat('小鱼干')
hua.climb()
子类 父类
子类的对象
想要使用某一个名字
- 如果自己有 就用自己的
- 如果自己没有 就用父类的
- 如果父类也没有 就报错
####如果想要使用的名字父类子类都有
- 既想使用子类的,也想使用父类的,那就在子类的方法中使用
- 父类名.方法名(self,参数1,参数2)
- super().方法名(参数1,参数2)
class A:pass
class A(object):pass
print(A.__bases__)
object类
object类是A的父类
#在python3当中,所有的类都继承object类,所有的类都是新式类
#所有的类的类祖宗 都是object
#父类是object的类 —— 新式类
class A(object):
pass
a = A() # 总是要调用init的,如果我们不写,实际上就调用父类object的__init__方法了
人狗大战
class Animal(object):
def __init__(self,name,blood,ad):
self.name = name
self.hp = blood
self.ad = ad
class Dog(Animal):
def __init__(self,name,blood,ad,kind):
super().__init__(name,blood,ad)
self.kind = kind
def bite(self,person):
person.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad))
class Person(Animal):
def __init__(self,name,hp,ad,sex):
super().__init__(name,hp,ad)
self.sex = sex
def fight(self,dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血'%(self.name,dog.name,dog.name,self.ad))
hei = Dog('小黑',300,20,'哈士奇')
alex = Person('alex',20,1,'不详')
alex.fight(hei)
print(hei.hp)
hei.bite(alex)
print(alex.hp)
抽象
继承
- 组合 :什么有什么
- 继承 :什么是什么的关系
- 先想描述的对象
- 先写出对象所对应的类
- 发现多个类之间有相同的代码
- 把相同的代码提取出来,搞成一个父类
先抽象,再继承
对象 -->类 -->基类
基类 -继承-> 子类 -实例化-> 对象
多继承
各种动物,每一种动物都是一个类
1. 青蛙、天鹅、老虎、鹦鹉
2. 青蛙 :走,游泳
3. 天鹅 :走,游泳,飞
4. 老虎 :走,游泳
5. 鹦鹉 :走,飞,说话
class FlyAnimal:
def fly(self):pass
class SwimAnimal:
def swim(self):pass
def eat():pass
class WalkAnimal:
def walk(self):pass
def eat():pass
class Frog(SwimAnimal,WalkAnimal): pass
class Tiger(SwimAnimal,WalkAnimal):pass
class Swan(FlyAnimal,SwimAnimal,WalkAnimal):pass
class Parrot(FlyAnimal,WalkAnimal):
def talk(self):
pass
- 多继承 是python语言中特有的继承方式
- java语言中不支持多继承的,C#也不支持多继承
- C++支持多继承
多继承和单继承是一样的
- 如果对象使用名字
- 是子类中有的,那么一定用子类的
- 子类没有,可以到多个父类中去寻找
##如果多个和父类都有,那么用谁的
钻石继承问题
class A(object):
def func(self):
print('a')
class B(A):
pass
# def func(self):
# print('b')
class C(A):
pass
# def func(self):
# print('c')
class D(B,C):
pass
# def func(self):
# print('d')
d = D()
d.func()
乌龟继承问题
class A(object):
def func(self):
print('a')
class B(A):
pass
# def func(self):
# print('b')
class C(A):
pass
# def func(self):
# print('c')
class D(B):
pass
# def func(self):
# print('d')
class E(C):
pass
# def func(self):
# print('e')
class F(D,E):
pass
# def func(self):
# print('f')
f = F()
f.func()
广度优先
C3算法
99%的情况都可以用眼睛看出来
但是仍然有1%的情况是看不出来的
C3算法是怎么计算的
class A(object):
def func(self):
print('a')
class B(A):
pass
def func(self):
print('b')
class C(A):
pass
def func(self):
print('c')
class F:
pass
def func(self):
print('f')
class D(A,F):
pass
# def func(self):
# print('d')
class E(B,C,F):
pass
def func(self):
print('e')
class G(C,D):
pass
def func(self):
print('g')
class H(E,G):
pass
def func(self):
print('h')
print(H.mro()) # 就是帮助我们来展示c3算法的继承顺序
C3算法
A= [AO]
B = B ,B节点的父类对应的顺序
B = B ,A节点顺序
B = B ,[AO]
提取第一个点
# 如果从左到右第一个类,
# 在后面的继承顺序中也是第一个,或者不再出现在后面的继承顺序中
# 那么就可以把这个点提取出来,作为继承顺序中的第一个类
B = [AO]
BA = [O]
B这个节点的继承顺序 :[BAO]
C = C,[AO]
C = [AO]
CA = [O]
C这个节点的继承顺序 :[CAO]
l(D) = D + [BAO]
D = [BAO]
[DBAO]
l(E) = E + [CAO]
[ECAO]
L[F] = F,[DBAO],[ECAO]
[F] = [DBAO],[ECAO]
[FD] = [BAO],[ECAO]
[FDB] = [AO],[ECAO]
[FDB] = [AO],[ECAO]
[FDBE] = [AO],[CAO]
[FDBEC] = [AO],[AO]
[FDBECA] = [O],[O]
[FDBECAO]
经典类和新式类
- py2.7 经典类
- 2个图
- 看 C3 mro
- 你自己去网上找一张图
class A(object):
def func(self):
print('a')
class B(A):
pass
def func(self):
super().func()
print('b')
class C(A):
pass
def func(self):
super().func()
print('c')
class D(B,C):
pass
def func(self):
super().func()
print('d')
b = B()
b.func()
#在多继承中,super就只和mro顺序有关系,和父类子类没有关系了
总结
- python的继承
- 提高代码的重用性,减少了代码的冗余
- 单继承
- 子类有的就用子类的
- 没有的就用父类的
- 如果父类子类都想用,super(),父类名.方法名
- 多继承
- 新式类 :继承object
- py2 要主动继承object才是新式类,默认是经典类
- 遵循的是广度优先算法,C3算法
- 有super()的,super遵循mro顺序的
- 有mro()方法
- 经典类 :不继承object
- 多个类之间去寻找方法的时候遵循深度优先
- 没有super方法也没有mro