发布时间:2018-04-13 20:38:05编辑:Run阅读(4379)
昨天内容复习
组合:什么有什么的关系(例:老师有生日)
class Birthday: def __init__(self, year, month, day): self.year = year self.month = month self.day = day def fmt(self): return '{}-{}-{}'.format(self.year, self.month, self.day) class Teacher: def __init__(self, name, birth): self.name = name self.birthday = birth def birth_month(self): self.birthday.fmt() # 引用组合对象的方法 return self.birthday.month # 引用组合对象的属性 birth = Birthday(1979, 10, 20) sam = Teacher('Tom', birth) # 将对象birth传进来作为实例化Teacher的属性 print(sam.birthday.year) # 调用组合对象中的属性 print(sam.birthday.fmt()) # 调用组合对象中的方法
执行结果
1979
1979-10-20
总结:组合就是把一个对象,作为另外一个类的属性
继承
猫
属性:名字 性别,品种
方法:吃 喝 爬树
狗
属性:名字 性别 品种
方法:吃 喝 看门
例
class Animal: def __init__(self, name, sex, kind): self.name = name self.sex = sex self.kind = kind def eat(self): print('{} is eating'.format(self.name)) def drink(self): print('{} is drinking'.format(self.name)) class Cat(Animal): def climb(self): print('{} is climbing'.format(self.name)) class Dog(Animal): def watch_door(self): print('{} is watching door'.format(self.name)) # 1 确认自己没有init方法 # 2 看看有没有父类 # 3 发现父类Animal有init # 4 看着父类的init方法来传参数 tom = Cat('小黑', '公', '波斯猫') sam = Dog('旺财', '公', '哈士奇') print(Cat.__dict__) # Cat.__dict__ Cat类的命名空间中的所有名字 print(tom.__dict__) # tom.__dict__ 对象的命名空间中的所有名字 print(Dog.__dict__) # Dog.__dict__ Dog类的命名空间中的所有名字 print(sam.__dict__) # sam.__dict__ 对象的命名空间中的所有名字 tom.eat() tom.climb() sam.drink() sam.watch_door()
执行结果
{'climb':
{'kind': '波斯猫', 'name': '小黑', 'sex': '公'}
{'__doc__': None, '__module__': '__main__', 'watch_door':
{'kind': '哈士奇', 'name': '旺财', 'sex': '公'}
小黑 is eating
小黑 is climbing
旺财 is drinking
旺财 is watching door
object类
class A:pass a = A() print(A.__bases__)
执行结果,可以看到A的父类为object,在python3中,只有新式类,默认继承object类
(
上面代码的执行步骤
1 创建了一个空的对象
2 调用init方法 -- class A里面没有写init方法,怎么不报错?执行了父类object的__init__方法
3 将初始化之后的对象返回调用出
在python3中所有的类都继承了object类
查看object的源码
里面包含了__init__方法
object带双下划线的方法,有2个名字,比如双下方法,魔术方法
任何实例化都经历3步,如果类没有init,由object完成了
例1
class Animal: def __init__(self, name, hp, ad): self.name = name self.hp = hp self.ad = ad def eat(self): print('{}吃药回血了'.format(self.name)) class Person(Animal): def attack(self, dog): # 派生方法 print('{}攻击了{}'.format(self.name, dog.name)) class Dog(Animal): def bite(self, person): # 派生方法 print('{}咬了{}'.format(self.name, person.name)) sam = Person('Sam', 10, 20) # 实例化一个对象sam, dog = Dog('花花', 10, 5) # 实例化一个对象dog print(sam.__dict__) print(dog.__dict__)
执行结果,打印对象属性
{'hp': 10, 'name': 'Sam', 'ad': 20}
{'hp': 10, 'name': '花花', 'ad': 5}
子类有的方法,叫派生方法
比如人有sex,狗有kind,现在需要在上面的例子中,给人额外加一个属性,狗额外加一个属性,那么首先想到的是在init里面加,如下
例
class Animal: def __init__(self, name, hp, ad): self.name = name self.hp = hp self.ad = ad def eat(self): print('{}吃药回血了'.format(self.name)) class Person(Animal): def __init__(self, sex): self.sex = sex def attack(self, dog): # 派生方法 print('{}攻击了{}'.format(self.name, dog.name)) class Dog(Animal): def __init__(self, kind): self.kind = kind def bite(self, person): # 派生方法 print('{}咬了{}'.format(self.name, person.name)) sam = Person('男') # 实例化类Person,传一个参数性别 dog = Dog('哈士奇') # 实例化类Dog,传一个参数品种 print(sam.__dict__) # 打印对象sam的属性 print(dog.__dict__) # 打印对象dog的属性
执行结果
{'sex': '男'}
{'kind': '哈士奇'}
why?为什么之前的属性都没有了,因为自己有了init后,它不会执行父类的init方法,那么如何执行父类的init呢?
有两种方法,第一种
class Animal: def __init__(self, name, hp, ad): self.name = name self.hp = hp self.ad = ad def eat(self): print('{}吃药回血了'.format(self.name)) class Person(Animal): def __init__(self, name, hp, ad, sex): Animal.__init__(self, name, hp, ad) self.sex = sex def attack(self, dog): # 派生方法 print('{}攻击了{}'.format(self.name, dog.name)) class Dog(Animal): def __init__(self, name, hp, ad, kind): Animal.__init__(self, name, hp, ad) self.kind = kind def bite(self, person): # 派生方法 print('{}咬了{}'.format(self.name, person.name)) sam = Person('Sam', 10, 20, '男') dog = Dog('花花', 10, 5, '哈士奇') print(sam.__dict__) print(dog.__dict__)
执行结果
{'ad': 20, 'name': 'Sam', 'sex': '男', 'hp': 10}
{'kind': '哈士奇', 'ad': 5, 'name': '花花', 'hp': 10}
可以看到,父类的属性也继承了,自己添加的属性也有,怎么实现的?
当执行init之前,开辟内存空间,self执行的是同一块内存空间,sam里面的self,指向都是一样的,在同一个类里面,self指向的都是同一个,如下图
第二种写法
class Animal: def __init__(self, name, hp, ad): self.name = name self.hp = hp self.ad = ad def eat(self): print('{}吃药回血了'.format(self.name)) class Person(Animal): def __init__(self, name, hp, ad, sex): super().__init__(name, hp, ad) self.sex = sex def attack(self, dog): # 派生方法 print('{}攻击了{}'.format(self.name, dog.name)) class Dog(Animal): def __init__(self, name, hp, ad, kind): super().__init__(name, hp, ad) self.kind = kind def bite(self, person): # 派生方法 print('{}咬了{}'.format(self.name, person.name)) sam = Person('Sam', 10, 20, '男') dog = Dog('花花', 10, 5, '哈士奇') print(sam.__dict__) print(dog.__dict__)
执行结果
{'name': 'Sam', 'hp': 10, 'sex': '男', 'ad': 20}
{'name': '花花', 'hp': 10, 'kind': '哈士奇', 'ad': 5}
在单继承中,super负责找到当前类(也就是Person和Dog的父类Animal)所在的父类,在这个时候不需要再手动传self
修改上面例子,增加新的需求:人吃药要钱,狗吃药不要钱
class Animal: def __init__(self, name, hp, ad): self.name = name self.hp = hp self.ad = ad def eat(self): print('eating in Animal') self.hp += 20 class Person(Animal): def __init__(self, name, hp, ad, sex): super().__init__(name, hp, ad) self.sex = sex self.money = 100 # 设置初始钱为100 def attack(self, dog): # 派生方法 print('{}攻击了{}'.format(self.name, dog.name)) def eat(self): super().eat() # super()方法找到父类,父类点eat(),执行父类里面的eat()方法 print('eating in Person') self.money -= 50 class Dog(Animal): def __init__(self, name, hp, ad, kind): super().__init__(name, hp, ad) self.kind = kind def bite(self, person): # 派生方法 print('{}咬了{}'.format(self.name, person.name)) sam = Person('Sam', 10, 20, '男') dog = Dog('花花', 10, 5, '哈士奇') sam.eat() print(sam.__dict__) print(dog.__dict__)
执行结果
eating in Animal
eating in Person
{'sex': '男', 'ad': 20, 'money': 50, 'name': 'Sam', 'hp': 30}
{'ad': 5, 'kind': '哈士奇', 'name': '花花', 'hp': 10}
继承
父类是新式类,那么继承的子类全部都是新式类,python3里面没有经典类
单继承 新式类
多继承 新式类(也叫钻石继承)
例子
class A: def func(self): print('A') class B(A): def func(self): print('B') class C(A): def func(self): print('C') class D(B,C): def func(self): print('D') d = D() d.func()
执行结果,why?
D
龟壳模型
新式类 多继承 寻找名字的顺序 遵循广度优先
super在多继承中,是找下一个节点的,而不是找父类的!
总结,在python3中都是新式类,使用的是广度优先原则
super()
在单继承中就是单纯的寻找父类
在多继承中就是根据子节点所在图的mro顺序寻找下一个类
例子
class A: def func(self): print('A') class B(A): def func(self): print('B') class C(A): def func(self): print('C') class D(B): def func(self): print('D') class E(C): def func(self): print('E') class F(D,E): def func(self): print('F') st = F() print(F.mro())
使用F.mro()打印出寻找类的顺序
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
在python2.x中,经典类多继承使用深度优先原则
在python2.x中,不手动继承object类,都属于经典类
深度优先,一条路走到底,找不到就会回来找其他的
经典类:在python2.x版本才存在,且必须不继承object
遍历的时候遵循深度优先算法
没有mro方法
没有super()方法
新式类:在python2.x版本中,需要继承object,才是新式类
遍历的时候遵循广度优先算法
在新式类中,有mro方法
有super()方法,但是在2.x版本的解释器中,必须传参数(子类名,子类对象)
47605
45985
36909
34469
29080
25713
24566
19714
19245
17756
5565°
6155°
5691°
5737°
6705°
5483°
5484°
5988°
5965°
7295°