继承
1.单继承
父类也叫基类
子类也叫派生类
如下所示,继承的关系:
继承的书写格式:
class 子类(父类):
方法
实例:
class Animal:
def eat(self):
print("-----吃-------")
def drink(self):
print("-----喝--------")
class Dog(Animal):
def drak(self):
print("汪汪叫")
a=Animal()
a.eat()
b= Dog()
b.eat()
孙类是可以继承爷爷类的,如下所示:
class Animal:
def eat(self):
print("---吃-----")
def drink(self):
print("----喝-----")
def sleep(self):
print("----睡觉-----")
class Dog(Animal):
def bark(self):
print("---汪汪叫----")
class Xiaotq(Dog):
def fly(self):
print("----飞-----")
xiaotq = Xiaotq()
xiaotq.fly()
xiaotq.bark()
xiaotq.eat()
2.重写
子类和父类中拥有方法名相同的方法,说明子类重写了父类的方法 重写的作用:父类中已经有了这个方法,但子类想修改里面的内容,直接 修改父类是不好的,就需要用到重写
例如:
class Animal:
def eat(self):
print("---吃-----")
def drink(self):
print("----喝-----")
def sleep(self):
print("----睡觉-----")
class Dog(Animal):
def bark(self):
print("---汪汪叫----")
class Xiaotq(Dog):
def fly(self):
print("----飞-----")
def bark(self):
print("----狂叫-----")
xiaotq = Xiaotq()
xiaotq.fly()
xiaotq.bark()
xiaotq.eat()
这样做,父类的方法是不会被调用的,需要用以下方式:
class Animal:
def eat(self):
print("---吃-----")
def drink(self):
print("----喝-----")
def sleep(self):
print("----睡觉-----")
class Dog(Animal):
def bark(self):
print("---汪汪叫----")
class Xiaotq(Dog):
def fly(self):
print("----飞-----")
def bark(self):
print("----狂叫-----")
#调用被重写的父类的方法
#1 必须加上self
Dog.bark(self)
#2
super().bark()
xiaotq = Xiaotq()
xiaotq.fly()
xiaotq.bark()
xiaotq.eat()
3、多继承
就是一个子类继承多个父类:
多 继 承 的 例 子 , 如 下 :
# -*- coding:utf-8 -*-
'''
@Author: 董咚咚
@contact: 2648633809@qq.com
@Time: 2023/7/31 17:02
@version: 1.0
'''
class Base(object):
def test(self):
print("-----base")
class A(Base):
def test1(self):
print("-----test1")
class B(Base):
def test2(self):
print("-----test2")
class C(A,B):
pass
c = C
c.test1()
c.test2()
c.test()
C也能继承Base
注:多继承中,每个父类都有相同的方法,子类继承时,会有一个继承顺 序
想要查看该顺序的调用流程可以使用以下方法:
print(子类类名.__mro__)
最后调用的是object方法,如果object方法也不存在,说明类中没有这个方 法
class Base(object):
def test(self):
print("-----Base")
class A(Base):
def test(self):
print("----A")
class B(Base):
def test(self):
print("----B")
class C(A,B):
def test(self):
print("-----C")
c=C()
c.test()
方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的 方法,
实例如下:
class Parent : # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
# super() 函数是用于调用父类(超类)的一 个方法。
对于”super(Child, self).foo()”可以理解为, 首先找到Child的父类Parent,然后调用父类的foo方法, 同时将Child的实例self传递给foo方法。
当心掉进Python多重继承里的坑
不惜一切代价地避免多重继承,它带来的麻烦比能解决的问题都多。如果 你非要用,那你得准备好专研类的层次结构,以及花时间去找各种东西的 来龙去脉吧
只有在代码之间有清楚的关联,可以通过一个单独的共性联系起来的时候 使用继承,或者你受现有代码所限非用不可的话,那也用吧 或者可以试试组合,组合则是利用模块和别的类中的函数调用实现了相同的 目的
一个例子,我们有一个基类,该基类有一个call_me方法,有两个子类重写 了这个方法,然后第3个类通过多重继承扩展了两个方法。这称为钻石继 承。
从技术上来说,在python3的所有多重继承都是钻石继承,因为所有的类都 从object继承,
上图中的object.__init__同样是一个钻石问题。
把上图转化成代码如下:
class BaseClass:
num_base_calls = 0
def call_me(self):
print("Calling method on Base Class")
self.num_base_calls += 1
class LeftSubclass(BaseClass):
num_left_calls = 0
def call_me(self):
BaseClass.call_me(self)
print("Calling method on Lef Subclass")
self.num_left_calls += 1
class RightSubclass(BaseClass):
num_right_calls = 0
def call_me(self):
BaseClass.call_me(self)
print("Calling method on Right Subclass")
self.num_right_calls += 1
class Subclass(LeftSubclass, RightSubclass):
num_sub_calls = 0
def call_me(self):
LeftSubclass.call_me(self)
RightSubclass.call_me(self)
print("Calling method on Subcalss")
self.num_sub_calls += 1
s = Subclass()
s.call_me()
print(s.num_sub_calls, s.num_left_calls, s.num_right_calls, s.num_base_calls)
调用并得到如下输出:
Calling method on Base Class
Calling method on Lef Subclass
Calling method on Base Class
Calling method on Right Subclass
Calling method on Subcalss
1 1 1 2
基类的call_me被调用了两次。但这不是我们想要的,如果在做实际的工 作,
这将导致非常严重的bug,如银行存款存了两次。
对于多重继承,我们只想调用“下一个”方法,而不是父类的方法。
实际上, 下一个方法可能不属于当前类或者当前类的父类或者祖先类。
关键字super可以解决这个问题,
如下是代码重写:
class BaseClass:
num_base_calls = 0
def call_me(self):
print("Calling method on
Base Class")
self.num_base_calls += 1
class LeftSubclass(BaseClass):
num_left_calls = 0
def call_me(self):
super().call_me()
print("Calling method on Lef Subclass")
self.num_left_calls += 1
class RightSubclass(BaseClass):
num_right_calls = 0
def call_me(self):
super().call_me()
print("Calling method on Right Subclass")
self.num_right_calls += 1
class Subclass(LeftSubclass, RightSubclass):
num_sub_calls = 0
def call_me(self):
super().call_me()
print("Calling method on Subcalss")
self.num_sub_calls += 1
s = Subclass()
s.call_me()
print(s.num_sub_calls, s.num_left_calls, s.num_right_calls, s.num_base_calls)
执行结果如下:
Calling method on Base Class
Calling method on Right Subclass
Calling method on Lef Subclass
Calling method on Subcalss
1 1 1 1
首先,Subclass的call_me方法调用了super().call_me(),其实就是引用了LeftSubclass.call_me()方法。然后LeftSubclass.call_me()调用了super().call_me(),
但是这时super()引用了RightSubclass.call_me()。 需要特别注意:super调用并不是调用LeftSubclass的超类(就是BaseClass)的方法。
它是调用RightSubclass,虽然它不是LeftSubclass的父类!这就是下一个方 法, 而不是父类方法。RightSubclass然后调用BaseClass,并且通过super调用保 证在类的 层次结构中每一个方法都被执行一次。
看图分析:
1、CClass类的work()方法调用了super.work,其实是引用了AClass.work()
2、在AClass.work()中,调用了super.work(),这时候是引用了BClass.work(),而不是BaseClass.work(),这就是所谓的下一个方法
3、接着在BClass.work()中调用了super.work()方法,
这时候才是去调用BaseClass.work()方法
super的牛逼之处
1、在类的继承层次结构中,只想调用"下一个方法",而不是 父类的方法
2、super的目标就是解决复杂的多重继承问题(基类被调用 两次的问题)
3、super是绝对的保证,在类的继承层次结构中每一个方法 只被执行一次
经典类和新式类
所有直接继承或者间接继承object的类,都是新式类,object称之为根类, 意思时所有类都是源自object类
• 为什么这么设计? 创建对象时,需要申请内存空间,创建新的名称空间,将对象的属性放入 名称空间,
这一复杂的基础操作都是由object完成的。简单来说就是object提供了一些 常用的基础操作
注意:
1.在python3中,所有类都是object的子类,所有类都是新式类
2.在python2中,默认的是经典类,不会继承object
#区别
#python3中定义类
class Cls():
print('python3中定义类')
#python2中
class Cls(Object):
print('python2中定义类')