单继承
封装根据职责将属性和方法封装到一个抽象的类
继承可以实现代码的重用,相同的代码不需要重复编写
1)语法
class 类名(父类名):
pass
子类继承自父类,可以直接使用父类已经封装好的方法
子类应该根据职责,封装子类特有的属性和方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Animal: #def __init__(self): def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(Animal): def bark(self): print("汪汪") wangcai = Dog() wangcai.eat() wangcai.run() wangcai.drink() wangcai.sleep() wangcai.bark()
2)专业术语
子类,父类,继承
派生类,基类,派生
3)继承的传递性
子类拥有父类以及父类的父类中封装的属性和方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Animal: #def __init__(self): def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(Animal): def bark(self): print("汪汪") class xiaotianquan(Dog): def fly(self): print("我会飞") xtq = xiaotianquan() xtq.fly() xtq.run() xtq.bark() xtq.drink() xtq.sleep() xtq.bark()
1.2 方法的重写
override
重写父类的两种情况
1 覆盖父类的方法
在子类中定义一个跟父类同名的方法
重写之后,在运行时,只会调用子类中重写的方法,而不会调用父类封装的方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Animal: #def __init__(self): def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(Animal): def bark(self): print("汪汪") class Cat(Animal): def cache(self): print("抓老鼠") class xiaotianquan(Dog): def fly(self): print("我会飞") # 覆盖父类方法 def bark(self): print("神一样的叫") xtq = xiaotianquan() xtq.fly() xtq.run() xtq.bark()
2 对父类方法进行扩展
子类的方法实现 包含有父类的方法实现
super().父类方法
super是特殊类,() 创建对象,最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现
1在子类中重新父类的方法
2在需要的地方使用super().父类方法来调用父类方法的执行
3代码的其他位置,针对子类的需求,编写子类特有的代码实现
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Animal: #def __init__(self): def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(Animal): def bark(self): print("汪汪") class Cat(Animal): def cache(self): print("抓老鼠") class xiaotianquan(Dog): def fly(self): print("我会飞") # 覆盖父类方法 def bark(self): # 1 针对子类特有的需求,编写代码 print("神一样的叫") # 2 使用super()调用原本在父类封装的方法 super().bark() # 3 增加其他子类的代码 print("$%$$%") xtq = xiaotianquan() xtq.fly() xtq.run() xtq.bark()
python2.0 需要调用父类的方法,父类名.方法(self),不推荐使用。如果使用子类名调用方法,会形成递归调用,出现死循环
Dog.bark(self)
1.3 父类的私有属性和私有方法
1 子类不能再自己的方法内部,直接访问父类的私有属性或者私有方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class A: def __init__(self): self.__num1 = 1 self.num2 = 10 def __test(self): print("%d %d" % (self.__num1,self.num2)) class B(A): def demo(self): # 1 不能访问父类的私有属性 #print("%d" % self._num1) # 2 不能调用父类的私有方法 # self.__test() pass # 创建一个子类对象 b = B() # 在外界不能使用父类的私有属性 或者 私有方法 print(b.num2) #b.__test()
2 子类可以通过父类的公用方法间接访问到私有属性或者私有方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class A: def __init__(self): self.__num1 = 1 self.num2 = 10 def __test(self): print("私有方法%d %d" % (self.__num1,self.num2)) def test(self): print("父类的公有方法%d " % self.__num1) self.__test() class B(A): def demo(self): # 1 不能访问父类的私有属性 #print("%d" % self._num1) # 2 不能调用父类的私有方法 # self.__test() # 3 访问父类的公有属性 print("%d" % self.num2) # 4 调用父类的公有方法 self.test() # 创建一个子类对象 b = B() b.demo() # 在外界不能使用父类的私有属性 或者 私有方法 #print(b.num2) #b.__test()
多继承
子类有多个父类,并且具有父类的属性和方法
class 子类名(父类名1,父类名2..):
pass
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class A: def test(self): print("test 方法") class B: def demo(self): print("demo 方法") class C(A, B): pass # 创建对象 c = C() c.test() c.demo()
如果父类之间存在同名的属性或者方法,应该尽量避免使用继承
MRO 方法搜索顺序(知道)
针对类提供了一个内置属性 __MRO__可以看方法的搜索顺序
在当前类中找到方法,查找下一个类,最后一个类,从左往右
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class A: def test(self): print("A test 方法") def demo(self): print("A demo 方法") class B: def test(self): print("B test 方法") def demo(self): print("B demo 方法") class C(A, B): pass # 创建对象 c = C() c.test() c.demo() # 确定对象调用方法的顺序 print(C.__mro__)
A test 方法
A demo 方法
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
python object 所有类的基类
新式类 和 旧式(经典)类
新式类 以object为基类
旧式(经典)类 不以object为基类 不建议使用
python 2.0 没有指定父类,不使用object
python 3.0 默认使用object作为该类的基类
新式类 和 旧式(经典)类会影响方法搜索顺序
如果没有父类,建议统一继承自object
class 类名(object):
pass
多态