面向对象2:类空间,类关系
类空间问题
何处可以添加对象属性
class Human:
mind = "有思想"
def __init__(self,name):
self.name = name
def rework(self,work):
self.work = work
man = Human("tom")
man.age = 18 #类外部可以
man.rework("IT") #类内部方法可以
print(man.__dict__)
# {'name': 'tom', 'age': 18, 'work': 'IT'}
对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加
添加类的静态属性
class Human:
mind = "有思想"
def __init__(self,name):
self.name = name
def rework(self,work):
self.work = work
def sethair(self):
Human.hair = "头发"
def setfood(self):
Human.food = "杂食"
Human.eyes = "眼睛"
Human.sethair("anyone") #类调用类的方法给类添加静态属性
man = Human("Jarry")
man.setfood() #对象调用类中的方法给类添加静态属性
print(Human.__dict__)
对象是找到类的属性
对象查找属性的顺序:先从对象空间找 >>类空间找 >>父类空间 >>...
类名查找属性的顺序:先从本类空间找 >>父类空间 >>...
类与类之间的关系
类与类之间的关系
依赖关系:将一个类的对象或者类名传到另一个类的方法中
class Door: def __init__(self,quality): self.quality = quality def opened(self): print("%s门被打开"%self.quality) class Human: def __init__(self,name): self.name = name def open(self): print("%s喊芝麻开门"%self.name) door_1.opened() door_1 = Door("石头") human_1 = Human("阿凡提") human_1.open() # 阿凡提喊芝麻开门 # 石头门被打开
关联关系:将一个类的对象或者类名封装到另一个类的对象的属性中
聚合关系:关联关系的一种特例,
组合关系:关联关系的一种特例,将一个类的对象或者类名封装到另一个类的对象的属性中
实现关系:
继承关系:
继承
继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充
class Animal: def __init__(self,sex,age): self.sex = sex self.age = age def eat(self): print("进食能力") class Cat(Animal): #Cat类继承了Animal的属性 eyes = "夜视" #Cat类添加自己的属性 def eat(self): print("爱吃鱼") class Dog(Animal): pass c1 = Cat("母",1) d1 = Dog("公",2) print(c1.age) print(c1.eyes) c1.eat() d1.eat() # 1 # 夜视 # 爱吃鱼 # 进食能力
继承的优点:
1,增加了类的耦合性(耦合性不宜多,宜精)。
2,减少了重复代码。
3,使得代码更加规范化,合理化
继承的分类
就上面的例子:
Animal叫做:父类,基类,超类。
Cat Dog叫做:子类,派生类。
python2中有两种类:
经典类:Python2.2之前一直使用的是经典类,经典类在基类的根如果什么都不写,没有父类
新式类:python2.2之后出现了新式类,新式类基类的根是object,既所有类都继承了object类
单继承
类名,对象执行父类方法和执行顺序
class Animal:
hair = "有毛"
def __init__(self,sex,age):
self.sex = sex
self.age = age
def eat(self):
print("填饱肚子")
def sleep(self):
print("日落而息")
class Cat(Animal):
def sleep(self): #先执行本类中的eat方法,如果没有才执行父类中的
print("昼伏夜出")
print(Animal.hair) #子类调用父类属性
Animal.eat("anyone") #子类调用父类方法
Animal.sleep("111") #子类调用父类方法
c1 = Cat("母",1,)
print(c1.hair) #对象调用本类的父类属性
c1.eat() #对象调用本类的父类方法
c1.sleep() #对象调用本类的父类方法,如果本类有,就执行本类的,不再执行父类方法
# 有毛
# 填饱肚子
# 日落而息
# 有毛
# 填饱肚子
# 昼伏夜出
同时执行本类与父类的方法
父类.方法()
class Animal: def __init__(self,sex,age): print("Animal类中") self.sex = sex self.age = age class Cat(Animal): def __init__(self,sex,age,hair): print("Cat类中") self.hair = hair Animal.__init__(self,sex,age) #不能省略self c1 = Cat("公",2,"短毛") # Cat类中 # Animal类中
super().func()跳过本类(默认)查找func方法并执行
class Animal: def __init__(self,sex,age): print("Animal类中") self.sex = sex self.age = age class Cat(Animal): def __init__(self,sex,age,hair): print("Cat类中") self.hair = hair super().__init__(sex,age) #不写self c1 = Cat("公",2,"短毛") # Cat类中 # Animal类中
多继承
class ShenXian: # 神仙 def fly(self): print("神仙都会飞") class Monkey: # 猴 def chitao(self): print("猴⼦喜欢吃桃⼦") class ShenHou(ShenXian, Monkey): # 孙悟空是神仙,也是只猴 pass sxz = ShenHou() # 孙悟空 sxz.chitao() # 会吃桃⼦ sxz.fly() # 会飞
当两个父类中出现了重名方法的时候,调用哪一个父类的方法?
既如何查找父类方法?即MRO(method resolution order“方法分辨顺序”) 问题。
在python中这是一个很复杂的问题.。因为在不同的python版本中使用的是不同的算法来完成MRO的.
经典类的多继承
咋经典类中采用的是深度优先。
按照123456的顺序即为深度优先
按照142356的顺序则为广度优先
新式类的多继承mro()
mro序列
MRO是一个有序列表L,在类被创建时就计算出来。
通用计算公式为
Child继承于Base1和Base2
mro(Child(Base1,Base2)) = [Child] + merge(mro(Base1),mro(Base2),[Base1,Base2])
如果继承于1个基类:
Child继承于Base
mro(Child) = mro(Child(Base))
= [Child] + merge(mro(Base),[Base])
= [Child] + merge([Base] + [Base])
= [B,A]
如果继承于多个基类:
Child继承于Base1,Base2,Base3,...
mro[Child]
= [Child] + merge(mro(Base1), mro(Base2), mro(Base3), ...,[Base1, Base2, Base3,...])
计算结果为一个列表,列表中至少有一个元素类,即本类Child。
merge是C3算法的核心。
merge操作:
表头:列表的第一个元素
表尾:列表表头以外的元素集合(可为空)
如计算merge( [E,O], [C,E,F,O], [C] ) 有三个列表 : ① ② ③ 1 merge不为空,取出列表①的表头E,判断
(E是否在这些表尾的集合中,在>>跳过,不在>>取出并从所有表头中删除) 各个列表的表尾分别是[O], [E,F,O],[],E在这些表尾的集合中,因而跳过当前列表 2 取出列表②的表头C,进行判断 C不在各个列表表尾的集合中,因而将C拿出到merge外,并从所有表头删除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 3 进行下一次新的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] ) # 单继承mro(D(O))=[D,O] = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D = [B,D,E] + merge([O] , [O]) = [B,D,E,O] mro(C) = mro( C(E,F) ) = [C] + merge( mro(E), mro(F), [E,F] ) = [C] + merge( [E,O] , [F,O] , [E,F] ) = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除 = [C,E,F] + merge([O] , [O]) = [C,E,F,O] 原式= [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]) # 跳过E = [A,B,D,C] + merge([E,O], [E,F,O]) = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O = [A,B,D,C,E,F] + merge([O], [O]) = [A,B,D,C,E,F,O] ---------------------
面向对象