继承
继承的简介
- 可以提高代码的复用性
- 让类与类之间产生了关系,有了这层关系,才有了多态
- 继承是面向对象的三大特性之一
如果在原来类的基础上,想增加一些功能,或是很多类中有大量重复的功能
- 直接修改原类,修改起来比较麻烦,且会违反ocp原则
- 直接创建一个新类,也比较麻烦,大量重复的代码
- 新的类继承原来的类,继承原类的属性和方法
如何使用继承
定义类时,可以在类后面加上括号,括号内指定的是当前类的父类(超类,基类,super)
class Animal():
def Run(self):
print('狗狗跑')
def Sleep(self):
print('狗狗睡着了')
class Dog(Animal):
def Home(self):
print('狗看家')
d = Dog() # 通过Dog类对象,创建新的对象d
d.Run() # 通过实例d调用Animal中的Run方法
d.Home() # 通过实例d调用Dog中的Home方法
r = isinstance(d, Dog) # isinstance可以检查实例d是不是Dog的实例对象
print(r)
r1 = isinstance(d, Animal) # d即是Dog的实例也是Animal的实例
print(r1)
r2 = isinstance(Dog(), Animal) # 检测Dog(),是不是Animal的对象,他可以检测继承
print(r2)
# 狗狗跑
# 狗看家
# True
# True
# True
isinstance()
- 用来判断一个对象是否是一个已知的类型】
- 与type类似,区别在于:
- type()不会认为子类是一种父类类型,不考虑继承关系
- isinstance()考虑继承关系
object
- 如果在创建类的时候省略了父类,则默认父类是object
- object是所有类的父类,所有的类都继承object
issubclass
- 检查一个类是不是另一个类的子类
class A:
pass
class B(A):
pass
r = issubclass(B, A)
print(r)
# True
方法的重写
如果在子类中有和父类重名的方法,通过子类的实例去调用方法时,会调用子类的方法而不是父类的方法,这个特点称之为方法的重写(覆盖 cover)
class A:
def Call(self):
print('A')
class B(A):
def Call(self):
print('B')
# class C(B):
# def A(self):
# print('C')
b = B()
b.Call()
#B
当我们去调用一个方法时
- 会优先在当前对象中寻找是否有该方法,如有,则调用
- 若无,则去当前对象的父类中寻找,有,则调用
- 若无,则去父类中的父类寻找,有,则调用,以此类推,知道找到object,如依然没有则报错
class A:
def Call(self):
print('A')
class B(A):
pass
class C(B):
pass
c = C()
c.Call()
# A
super
父类中的所有方法都会被子类继承,包括特殊方法
class Hero():
def __init__(self, name):
self._name = name
def Power(self):
print('control')
@property
def getter(self):
return self._name
# xxx.setter,xxx是getter方法的函数名
# name.setter,可以让setter方法直接用调用属性的方法调用,
# 且会将修改后的返回值返回给getter方法,并执行getter方法
@getter.setter
def updata(self, name):
self._name = name
class Dc(Hero):
pass
d = Dc('spiderman')
print(d.getter)
# spiderman
那么我们是否可以直接调用父类的__init__来初始化父类中的属性?
当然可以
class Hero():
def __init__(self, name):
self._name = name
def Power(self):
print('control')
@property
def getter(self):
return self._name
@getter.setter
def updata(self, name):
self._name = name
class Dc(Hero):
def __init__(self, name, age): # 我们调用了父类中的name同时加入了新的属性,但新的属性不会返回
self._name = name
self._age = age
d = Dc('batman', 36)
print(d.getter)
如果父类里有多个初始化属性,那我每个初始化属性都要重新打一遍,太麻烦
引入super
- super()可以获取当前类的父类
- 通过super()返回的对象,调用父类时不用加self,能省点事儿,能省一点是一点
class Hero():
def __init__(self, name, age, surpower):
self._name = name
self._age = age
self._surpower = surpower
def Introduce(self):
print('名字{} 年龄{} 超能力{}'.format(self._name, self._age, self._surpower))
@property
def getter(self):
return self._name, self._age, self._surpower # 已元组的形式返回
@getter.setter
def updata(self, name, age, surpower):
self._name = name
self._age = age
self._surpower = surpower
class Dc(Hero):
def __init__(self, name, age, superpower, position):
super().__init__(name, age, superpower)
self._position = position
@property
def p_get(self):
return self._position
@p_get.setter
def p_set(self,position):
self._position = position
d = Dc('batman', 36, 'rich', 'c位')
print(d.getter)
print(d.p_get)
# ('batman', 36, 'rich')
# c位
多重继承
- 在python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类(认多个爹)
- 在开发中,没有特殊情况不要使用多重继承,因为多重继承会让我们的代码过于复杂
- 如果多个父类中有重名的方法,则先会在第一个父类中寻找,然后是第二个。。。
- 前边的会覆盖后边的
- 多重继承的父类必须是同级别的,不能继承 类(父类),也就是“爷爷类”
- ‘bases ’可以用来获取当前类的所有父类,返回的是一个元组(tuple)
class A():
def text(self):
print('A')
class B():
def text(self):
print('B')
class C(A, B):
pass
class D(B, A):
pass
c = C()
print(C.__bases__)
c.text()
d = D()
d.text()
# (<class '__main__.A'>, <class '__main__.B'>)
# A
# B
多态
- 面向对象的三大特性之一
- 多态从字面上理解就是多种形态
lis = [1, 2, 3]
name = 'python'
print(len(lis))
print(len(name))
# 3
# 6
当我们使用len()方法时,我们可以用来检查列表的长度,也可以检查字符串的长度这就是一种多态,
如果没有多态,那么我们想知道列表的长度,可以使用len()方法,
而我们想知道字符串的长度,就需要别的方法了,比如loa()方法(没有这个方法,为了举例,编的)
多态:不同子类之间调用相同的放回,产生的效果不同
class Dog():
def __init__(self, dname):
self.name = dname
class Person():
def __init__(self, pname):
self.name = pname
class play():
def __init__(self, p_name, d_name):
self.people = p_name
self.dog = d_name
def Game(self):
print('%s play with %s'%(self.people, self.dog))
d = Dog('二哈')
p = Person('shell')
c = play(p.name, d.name)
c.Game()
# shell play with 二哈
play类中,只要传入参数就可以实现A play with B的功能,至于A&B是什么我们不需要关系,他可以是任何东西,实物,人
类中的属性和方法
class A(object):
num = 9
def __int__(self):
self._name = 'shell'
def text(self):
print('我是实例方法text', self)
a = A()
a.text()
A.text(a) # a.text()就等于A.text(a)
# 我是实例方法text <__main__.A object at 0x0000018B3768C588>
# 我是实例方法text <__main__.A object at 0x0000018B3768C588>
num:
- 类属性,直接在类中定义的属性就是类属性
- 类属性可以通过类或类的实例访问到
- 类属性只能通过实例对象修改,无法通过类对象修改
self._name: - 实例属性,通过实例对象添加的属性属于实例属性
- 实例属性只能通过实例属性来访问&修改,类对象无法访问&修改
text(self): - 实例方法,在类中以self为第一个参数的都是实例方法
- 实例方法再调用时,python会将调用的对象作为self传入
- 通过类对象调用实例方法时,不会自动传入self,需要手动
class A(object):
num = 9
def __int__(self):
self._name = 'shell'
def text(self):
print('我是实例方法text', self)
@classmethod
def text2(cls):
print('我是类方法', cls)
print(cls.num)
a = A()
A.text2()
a.text2() # a.text2()就等于A.text2()
# 我是类方法 <class '__main__.A'>
# 9
# 我是类方法 <class '__main__.A'>
# 9
类方法
- 类方法的第一个参数是cls,也会被自动传递,cls就是当前类对象
- 类方法可以通过类对象去调动,也可以通过实例对象调用
class A(object):
num = 9
def __int__(self):
self._name = 'shell'
def text(self):
print('我是实例方法text', self)
@staticmethod
def text3():
print('我是静态方法')
a = A()
A.text3()
a.text3()
# 我是静态方法
# 我是静态方法
静态方法
- 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到类中的函数
- 静态方法都是一些工具方法,和当前类无关