面向对象三大特性
1、封装 根据 职责 将属性和方法 封装到一个抽象的 类 中
2、继承 实现代码的重用,相同的代码不需要重复的编写
3、多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
01单继承
1.1继承的概念、语法和特点
继承的概念: 子类 拥有 父类 的所有方法和属性
class Animal: def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(): def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") def bark(self): print("汪汪叫") wangcai = Dog() wangcai.eat() wangcai.drink() wangcai.run() wangcai.sleep() wangcai.bark()
1)继承的语法
class 类名(父类名):
pass
class Animal: 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.drink() wangcai.run() wangcai.sleep() wangcai.bark()
-子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发
-子类 中应该根据职责,封装子类特有的 属性和方法
2)专业术语
-Dog类是Animal类的子类,Animal类是Dog类的父类,Dog类从Animal类继承
-Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生
3)继承的传递性
-C类从B类继承,B类又从A类继承
-那么C类就有B类和A类的所有属性和方法
子类 拥有父类以及父类的父类中封装的所有属性和方法
1.2方法的重写
-子类 拥有父类的所有方法和属性
-子类继承父类,可以直接享受父类中已经封装好的方法,不需要再次开发
应用场景:
-当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)
重写父类方法有两种情况:
1、覆盖父类的方法
2、对父类方法进行扩展
1)覆盖父类的方法
-如果开发中,父类的方法实现和子类的方法实现 完全不同
-就可以以覆盖的方式,在子类中重新编写父类的方法实现
具体实现方式,就相当于在子类中定义了一个和父类同名的方法并实现,重写后,在运行时,只会调用子类中重写的方法,而不会调用父类封装的方法
class Animal: def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(Animal): def bark(self): print("汪汪叫") def eat(self): print("我吃的一般") class XiaoTianQuan(Dog): def fly(self): print("我会飞") def eat(self): print("我吃的金贵") xtq = XiaoTianQuan() dog = Dog() dog.eat() xtq.eat()
2)对父类方法进行扩展
-如果开发中,子类的实现方法中包含父类的方法实现
父类原本封装的方法实现 是 子类方法的一部分
-就可以使用扩展的方式
1、在子类中重写父类的方法
2、在需要的位置使用super().父类方法来调用父类方法的执行
3、代码其他的位置针对子类的需求,编写子类特有的代码实现
class Animal: def eat(self): print("吃") def drink(self): print("喝") def run(self): print("跑") def sleep(self): print("睡") class Dog(Animal): def bark(self): print("汪汪叫") def eat(self): print("我吃的一般") class XiaoTianQuan(Dog): def fly(self): print("我会飞") def eat(self): print("哮天犬专属") # 根据需要增加 super().eat() print("我吃的金贵") # 根据需要增加 xtq = XiaoTianQuan() dog = Dog() dog.eat() xtq.eat()
关于Super
-在Python中super是一个特殊的类
-super()就是使用super类创建出来的对象
-最常使用的场景就是在重写父类方法时,调用在父类中封装的方法
备注: Python2.x有另一种方式,父类.方法(self),这里不多说明
1.3父类的私有属性和私有方法
1、子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
2、子类对象 可以通过父类的公有方法间接访问到私有属性或私有方法
-私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
-私有属性、方法通常用于做一些内部的事情
class A: def __init__(self): self.num1 = 1 self.__num2 = 1 def __test(self): print("你能使用?") def test(self): print("试试我呢") class B(A): def demo(self): print("%d" % self.num1) # 可以调用公共的属性 print("%d" % self.__num2) # 不能调用私有的属性 self.test() # 可以调用公共的方法 self.__test() # 不能调用私有的方法 a = B() a.demo()
不过,没有绝对的私有:
class A: def __init__(self): self.num1 = 1 self.__num2 = 1 def __test(self): print("你能使用?") def test(self): print("试试我呢") print("我自己使用%d" % self.__num2) # 父类在自己的非私有方法中调用私有属性 self.__test() # 分类在自己的非私有方法中调用私有方法 class B(A): def demo(self): print("%d" % self.num1) # 可以调用公共的属性 # print("%d" % self.__num2) # 不能调用私有的属性 self.test() # 可以调用公共的方法 # self.__test() # 不能调用私有的方法 a = B() a.demo()
02多继承
概念:
-子类 可以拥有多个父类,并且具有所有父类的属性和方法
-例如:孩子 会继承自己 父亲 和 母亲 的特性
语法:
class 子类名(父类1,父类2 . . .)
pass
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()
2.1多继承的使用注意事项
问题:
如果 不同的父类 中存在 同名的方法,子类对象 在调用方法时,会调用 哪一个父类方法?
因此:
应尽量避免这种容易产生混淆的情况!!--- 如果父类之间存在同名的属性或方法,应尽量避免使用多继承
class A: def test(self): print("A----test 方法") def demo(self): print("A----demo 方法") class B: def demo(self): print("B----demo 方法") def test(self): print("B----test 方法") class C(A, B): # 按照先继承的父类来处理 pass c = C() c.test() c.demo()
Python中的MRO
-Python中针对类提供了一个内置属性,__MRO__可以查看方法搜索顺序
-MRO是method resolution order,主要用于在多继承时判断方法、属性的调用路径
print(C.__mro__)
输出的结果
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
-在搜索方法时,是按照__mro__的输出结果从左至右的顺序查找的
-如果在当前类中找到方法,就直接执行,不再搜索
-如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
-如果找到最后一个类,还没有找到方法,程序就报错
2.2新式类与旧式类(经典)类
object是Python中为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看
-新式类:以object为基类的类,推荐使用
-旧式类:不以object为基类的类,不推荐使用
-在Python3.x中定义类时,如果没有指定父类,会默认使用object作为该类的基类(py3.x都是新式类)
-在Python2.x中定义类时,如果没有指定父类,也不会以object作为基类
新式类 和旧式类在多继承时----会影响到方法的搜索顺序