类的继承与多态
1. 类的继承
1.1 继承的实现
继承:子类继承父类的属性和方法
当子类对象去调用方法时,会先在子类中去查找 方法,如果有,那么就执行,如果没有找到,父类中去查找 该方法,如果找到执行找不到再到上一级类中去查找 直到找到object类,如果还没有那么就报错
格式:
class 子类名(父类名称,...):
pass
'''
子类继承父类的属性和方法
'''
class Father(object):
def __init__(self):
self.name = '电话'
def call(self,number):
print(f'正在给谁打电话{number}')
class Son(Father):
def crema(self,name):
print(f'给谁照相:{name}')
s = Son()
print(s.name)
s.call(123)
s.crema("tom")
1.2 子类不能直接使用父类的私有属性和方法
只能通过父类中的共有的方法来间接的进行使用
'''
子类继承父类的属性和方法
'''
class Father(object):
def __init__(self):
self.name = '电话'
self.__money = 99
def __show(self):
print('父类的私有方法')
def diaplay(self):
print('父类的共有方法')
#想访问父类中私有方法是能通过父类的共有方法进行间接的使用
self.__show()
def get_money(self):
return self.__money
class Son(Father):
def play(self):
print('子类的共有方法')
# 通过继承可以使用父类的共有方法
self.diaplay()
s = Son()
print(s.name)
# 私有属性不能访问
# print(s,money)
s.play()
print(s.get_money())
如果想使用父类中的私有属性和私有方法,那么就需要在父类中,为这些私有的属性和方法,提供相应的公有的接口方法来间接访问
1.3 子类初始化父类中的属性
父类名.方法名(self)
'''
子类初始父类的属性
类名.init方法
'''
class Father(object):
def __init__(self,name):
self.name = name
class Son(Father):
# 子类在定义了init犯法之后,执行的时候就不会继承调用父类中的init方法,就不会绑定父类中的属性
# 这个时候就需要我们手动的调用执行父类的int方法
# 注意这个时候就需要写入self这个参数
def __init__(self,name,age):
Father.__init__(self,name)
self.age = age
s = Son('tom',12)
print(s.name)
print(s.age)
1.4 子类重写父类的方法
class Father(object):
def show(self):
print('我是一个老中医哦')
class Son(Father):
def show(self):
# 要想执行父类中的方法
Father.show(self)
print('我是一个西医')
# 重写父类中的方法之后,调用的时候就不会执行父类中的方法
s = Son()
s.show()
1.5 多层继承和多继承
多层继承:纵向
'''
多层继承是纵向的
'''
class A(object):
def a(self):
print('a ...Run')
class B(A):
def b(self):
print('b ...Run')
class C(B):
def c(self):
print('c...Run')
class D(C):
def d(self):
print('d ...Run')
# 测试
d = D()
d.a()
d.d()
d.c()
d.d()
多层继承属性的初始化问题:
'''
多层继承是纵向的
'''
class A(object):
def __init__(self,a):
self.a = a
class B(A):
def __init__(self,a,b):
A.__init__(self,a)
self.b = b
class C(B):
def __init__(self,a,b,c):
B.__init__(self,a,b)
self.c = c
class D(C):
def __init__(self,a,b,c,d):
C.__init__(self,a,b,c)
self.d = d
# 测试
d = D(1,2,3,4)
print(d.a)
print(d.b)
print(d.c)
print(d.d)
print(d.__dict__)
print(D.__dict__)
多继承:
class Father(object):
def show_fa(self):
print('i am father ')
class Mother(object):
def show_mo(self):
print('mother')
class Som(Father,Mother):
def show(self):
print('son')
# 测试
s = Som()
s.show_fa()
s.show_mo()
多继承出现的父类多次进行初始化的问题:
'''
当我父类还有一个共同的父类的时候,就会出现重复执行的问题
共同的父类会被初始化多次
'''
class Person(object):
def __init__(self,p):
print('person run')
self.p =p
class Father(Person):
def __init__(self,p,name):
print('father run...')
Person.__init__(self,p)
self.name =name
class Mother(Person):
def __init__(self,p,age):
print('mother run...')
Person.__init__(self, p)
self.age= age
class Son(Father,Mother):
def __init__(self,p,name,age,a):
Father.__init__(self,p,name)
Mother.__init__(self,p,age)
self.a = a
s = Son(23,'tom',12,23)
print(s.p)
print(s.name)
print(s.age)
print(s.a)
print(Son.__mro__)
解决办法:
super()的应用
super(类名,self)的方式
'''
使用的是super(类名,self)的方式
'''
class Person(object):
def __init__(self,aaa):
print('Person Init ...')
self.aaa = aaa
class Father(Person):
def __init__(self,name,*args):
super(Father, self).__init__(*args)
print('Father Init ...')
self.name = name
class Mother(Person):
def __init__(self,age,*args):
super(Mother, self).__init__(*args)
print('Mother Init ...')
self.age = age
class Son(Father, Mother):
def __init__(self,aaa, name,age, gender):
# 参数二是当前类的实例对象
# 参数一是当前类名
# 在参数二对象的所属类的mro关系 中找参数一的下一个类进行实始化
super(Son, self).__init__(name,age,aaa)
print('Son Init ...')
self.gender = gender
# 测试
s = Son(1,2,3,4)
print(s.aaa)
print(s.name)
print(s.age)
print(s.gender)
print(Son.__mro__)
super简化
class Person(object):
def __init__(self,p):
self.p = p
class Father(Person):
def __init__(self,name,*args):
super().__init__(*args)
self.name = name
class Mother(Person):
def __init__(self,age,*args):
super().__init__(*args)
self.age = age
class Son(Father,Mother):
def __init__(self,p,name,age,h):
super().__init__(name,age,p)
self.h = h
s =Son(1,'tom',23,4)
print(s.p)
print(s.name)
print(s.age)
print(s.h)
print(Son.__mro__)
1.6 mro
类名.mro 得到了一个元组,元组中的元素是当前类在继承关系上的一个顺序
类继承的顺序的书写会影响mro的执行顺序,他是一个元组,不会改变
class A(object):
pass
class B(A):
pass
class C(A):
pass
# (<class '__main__.D'>,
# <class '__main__.B'>,
# <class '__main__.C'>,
# <class '__main__.A'>,
# <class 'object'>)
# class D(B,C):
# pass
class D(C,B):
pass
# (<class '__main__.D'>,
# <class '__main__.C'>,
# <class '__main__.B'>,
# <class '__main__.A'>,
# <class 'object'>)
print(D.__mro__)
方法也会根据mro来决定
class A(object):
def show(self):
print('a')
class B(A):
def show(self):
print('b')
class C(A):
def show(self):
print('c')
class D(C,B):
def show(self):
# 注意使用 类名.方法,和super的区别,
# super 不用写self
# B.show(self)
super().show()
print('d')
d = D()
d.show()
print(D.__mro__)
2. 多态
当调用一个方法名的时候,得到的结果不同
在一般的面向对象语言中,多态是由继承来实现的
但是在python中,python,天生具有多态性
class Father(object):
def cure(self):
print('只会古老的中医疗法')
class Son(Father):
def cure(self):
print('中西结合')
class Dog(object):
def bark(self):
print('won won...')
class Person(object):
def look(self,docter):
docter.cure()
p = Person()
p.look(Son())
p.look(Father())
# 没有这个方法就不会
# p.look(Dog()) AttributeError: 'Dog' object has no attribute 'cure'
3. 其他的补充
3.1 实例的属性和实例的方法
class A(object):
# 实例属性
def __init__(self,a):
self.a = a
# 实例方法
def show(self):
print('aaa')
# 调用
a = A(12)
# 查看实例属性
print(a.a)
# 使用实例方法
a.show()
# 类名不能调用实例属性和方法
# A.show()
# 因为类存在不一定有实例对象,实例的属性方法,只有实例可以调用
3.2 类的属性和类对象
class Room(object):
# 用于实现数据间的共享
name = '901'
# 实例方法:
def show(self):
print('实例方法中访问类的属性')
print(Room.name)
# 可以直接通过类名访问
print(Room.name)
# 实例也可以访问
c1 = Room()
print(c1.name)
c2 = Room()
print(c2.name)
# 更改时候通过类名更改才能使全局改变,使用实例只是把实例分配一个新的值的引用,并不会改变name原有的值
c1.name = '903'
print(c1.name)
print(c2.name)
Room.name = 905
print(c1.name)
print(c2.name)
c1.show()
3.3 属性和方法的保存位置dict魔法函数
class Dog(object):
def __init__(self,name):
self.name = name
self.__age = 1
def public_method(self):
print('public')
def __private_metod(self):
print('private')
d = Dog('tom')
jack = Dog('Jack')
print(d.__dict__)
print(jack.__dict__)
print(Dog.__dict__)
3.4 类方法和静态方法(大多数在工具类中使用)
类方法:@classmethod
'''
@classmethod修饰
当我们不需要实例化对象的时候
'''
class Test(object):
# classmethod是一个装饰器,他在执行代码的时候,会自动的把类类的对子昂参数传递到cls
@classmethod
def sum(cls,*args):
m = 0
for i in args:
m+=i
print(m)
# 不加@classmethod
def show(cls):
print('classmethod')
Test.sum(1,2,3,4)
Test.show(Test)
静态方法:@staticmethod
class Util(object):
@staticmethod
def encode(data,code):
print(f'数据{data}进行了编码{code}')
@staticmethod
def decode(data,code):
print(f'数据{data}进行了{code}解码')
Util.decode('123','utf-8')
u = Util()
u.encode('456','GBK')
总结:
1.实例方法:必须通过实例对象调用执行,第一个参数是调用方法的实例
2.类方法:但不需要产生实例的时候,类方法可以直接使用类名来进行调用,第一个参数cls,用来接收当前类对象,可以进行类方法之间的数据共享
3.静态方法:同类方法,但是今天方法不接受任何默认的参数