事物之间都会存在一些相对应的关系,在面向对象中,类与类之间存在着以下关系:
依赖关系
关联,组合,聚合关系,
实现关系,继承关系
01.依赖关系:
将一个类的类名或对象传入到另一个类的方法中
例1. 设计一个场景:把大象装进冰箱,这个场景中存在两个事物,一个是大象,另一个是冰箱
class Elephant: def __init__(self,name): self.name = name def open(self,obj): print('%s说:开门'%(self.name))
obj.be_opened() def close(self,obj): print('%s说:关门'%(self.name))
obj.be_closed() class Refrigerator: def __init__(self,name): self.name = name def be_opened(self): print('%s被打开了'%(self.name)) def be_closed(self): print('%s被关闭了'%(self.name)) ele_obj = Elephant('猛犸') haier = Refrigerator('海尔') xinfei = Refrigerator('新飞')
# 将冰箱类的实例化对象,传到大象类的方法中
ele_obj.open(haier)
ele_obj.close(haier)
02.组合关系:
组合:将一个类的对象或类名,封装到另一个类的对象的属性中
例2. 设计一个场景,男女朋友
class Boy: def __init__(self,name,gf = None): self.name = name self.gf = gf def have_dinner(self): if self.gf: print('%s和女朋友%s一起共度晚餐'%(self.name,self.gf.name)) else: print('%s自己一个玩'%(self.name)) class Girl: def __init__(self,name): self.name = name allen = Boy('allen') ruhua = Girl('如花') allen.gf = ruhua # self.gf 拿到的是一个内存地址 allen.have_dinner() # allen和女朋友如花一起共进晚餐
例3. 游戏人物相互攻击
class GameRole: def __init__(self,name,ad,hp): self.name = name self.ad = ad self.hp = hp def equipment(self,wea): self.wea = wea # 给人物对象封装一个属性,这个属性是武器类的实例化对象 class Weapon: def __init__(self,name,ad): self.name = name self.ad = ad def wea_attack(self,p1,p2): p2.hp -= p1.ad+self.ad print('%s用%s攻击了%s,%s掉了%s血,还有%s血'% (p1.name, self.name, p2.name, p2.name,p1.ad+self.ad, p2.hp )) # 实例化人物对象
yasuo = GameRole('亚索',20,200) mumu = GameRole('木木',10,200) # 实例化武器对象 sword = Weapon('太刀',10) hammer = Weapon('锤子',10) # 给人物封装武器属性 yasuo.wea = sword mumu.wea = hammer yasuo.wea.wea_attack(yasuo,mumu) mumu.wea.wea_attack(mumu.attack)
03.继承关系:
3.1.单继承
3.1.1通过类名或对象执行父类方法:
class Animal:
type_name = '动物类'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('in Animal eat')
class Person(Animal):
pass
1.执行父类方法
# 类名调用:
print(Person.eat(123))
print(Person.type_name)
# 对象调用:
obj = Person('小一',18,'男')
obj.eat() # in Animal eat
obj.type_name = '123'
print(obj.__dict__) # {'name':'小一','age':18,'sex':男,'type_name':'123'}
执行步骤:
(1)实例化对象obj,执行__init__方法,子类空间没有,就去父类空间找,父类空间如果没有,就继续往上找(python3中的父类默认为object)
(2)obj.eat(),先执行子类空间中的eat方法,没有就去父类空间中找
3.1.2同时执行子类和父类的方法:
class Animal:
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print('in Animal func')
class Person(Animal):
def func():
Animal.func(self) # 类名.方法名时,必须要传参
super().func() # super方法,func()中不用传参数
print('in Person func')
p1 = Person('小一',18)
p1.func() in Animal func in Person func
3.1.3同时执行子类和父类的__init__方法:
class Animal: def __init__(self,name,age): self.name = name self.age = age class Person(Animal): def __init__(self,name,age,sex): Animal.__init__(self,name,age) super().__init__(name,age) self.sex = sex p1 = Person('小一',18,'男') print(p1.__dict__) {'name':'小一','age':18,'sex':'男'}
3.1.4 super( )方法:
完全按照对象所在类的mro顺序执行,在多继承中,super(指定类名,self).方法名(),super中指定的类会被跳过,执行mro的下一个顺序的类的方法
class A:
def func1(self):
print('in A func1')
class B(A):
def func1(self):
super(B, self).func1() 跳过B,执行C
print('in B func1')
class C(A):
def func1(self):
print('in C func1')
class D(B,C):
def func1(self):
super(D, self).func1() 跳过D,执行B
print('in D func1')
obj = D()
obj.func1()
print(D.mro()) 继承顺序:D.B.C.A
3.2多继承
3.2.1 python中类的分类: 经典类,新式类
py2x版本中: py2.2之前只有经典类,不继承object类,遵循的是深度优先原则,从左至右一条路走到黑
py2.2之后,出现新式类,继承object类,遵循C3算法,mro顺序
py3x版本中: 所有的类都默认继承object类
3.2.2 经典类的多继承:
深度优先原则,从左至右一条路走到黑
mro顺序: Foo --> H --> G --> F --> E --> D --> B --> A --> C
3.2.3 新式类的多继承: 当两个父类出现了重名的方法时,遵循C3算法,mro顺序
(1)mro序列: 是一个有序的列表,在类被创建时就会计算出来
通用公式为:mro(Child(Base1,Base2)) = [Child] + merge(mro(Base1),mro(Base2),[Base1,Base2])
(2)继承至一个基类: classB(A)
mro(B) = mro(B(A)) = [B] + merge(mro(A),[A]) = [B] + merge([A]+[A]) = [B,A]
(3)继承至多个基类: classB(A1,A2,A3...)
mro(B) = merge(B(A1,A2,A3...)) = [B] + merge(mro(A1),mro(A2),mro(A2)...[A1,A2,A3...])
= ...
(4)表头和表尾:
表头: 列表的第一个元素
表尾: 除第一个元素外其他元素
如计算merge( [E,O], [C,E,F,O], [C] ) 1 2 3 01.merge不为空,取出第一个列表列表1的表头E,进行判断 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表 02.取出列表2的表头C,进行判断 C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除 merge( [E,O], [C,E,F,O], [C] ) = [C] + merge( [E,O], [E,F,O]) 03.进行下一次新的merge操作 ......
例:
mro(A) = mro(A(B,C)) = [A] + merge(mro(B),mro[C],[B,C]) mro(B) = mro(B(D,E)) = [B] + merge(mro(D),mro(E),[D,E]) = [B] + merge([D,O],[E,O],[D,E]) = [B] + [D] + merge([O],[E,O],[E]) = [B,D,E] + merge([O]) = [B,D,E,O]
mro(C) = mro(C(E,F)) = [C,E,F,O]
mro(A) = [A] + merge([B,D,E,O] + [C,E,F,O] + [B,C])
= [A,B] + merge([D,E,O] + [C,E,F,O] + [C])
= [A,B,D] + merge([E,O] + [C,E,F,O] + [C])
= [A,B,D,C] + merge([E,O] + [E,F,O])
= [A,B,D,C,E] + merge([O] + [F,O])
= [A,B,D,C,E,F,O]
4.面向对象的三大特性:封装,继承,多态
封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
优点:便于使用,提高复用性和安全性
继承:可以使子类具有父类的各种属性和方法,而且不需要再次编写相同的代码,在子类继承父类的同时,可以重新定义某些属性,重写某些方法,即覆盖父类中原有的属性和方法,使子类具有不同于父类的功能,此外,给子类追加新的属性和方法也是很常见的做法.
继承的优点: 增强代码的耦合性,减少重复代码,使代码更加规范化,合理化
多态:指一类事物有多种形态.python默认支持多态,一个变量可以是多种数据类型
鸭子类型: 如果看起来是鸭子,那它就是鸭子,两个类虽没有任何关系,但隐形中遵循了一个标准
优点:1.统一标准,减少了词汇量,建立了一种弱关联;2.两个类没有任何的耦合性,但是可以产生关系,A的对象会使用B类的方法