面向对象下 继承、方法重写、super()、多重继承、多态
一、继承简介
-
继承是面向对象三大特性之一
-
作用:通过继承可使一个类获取到其他类中的属性和方法
-
在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类)
-
继承提高了类的复用性,让类与类产生了关系。
-
有了继承这个特性,才有了多态的特性
-
class Animal: def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') class Dog(Animal): # 类里无代码,可调用父类的方法 pass d = Dog() d.run() d.sleep() # 动物会跑。。。。。 # 动物睡觉。。。。。 class Animal: def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') class Dog(Animal): # 除继承父类外,也可有Dog类独有的方法 def speak(self): print('汪汪汪汪。。。。。') d = Dog() d.run() d.sleep() d.speak() # 动物会跑。。。。。 # 动物睡觉。。。。。 # 汪汪汪汪。。。。。 class Animal: def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') class Dog(Animal): def speak(self): print('汪汪汪汪。。。。。') d = Dog() r = isinstance(Dog,Animal) r1 = isinstance(d,Animal) # 判断d是否是Animal的实例 r2 = isinstance(d,Dog) print(r,r1,r2) # False True True # 在创建类的时候,如果省略了父类,则默认父类是object # object是所有类的父类,所有类都继承于object class Person: pass # issubclass() 检测一个类是否是另一个类的子类 r = issubclass(Dog,Animal) r1 = issubclass(Dog,Person) r3 = issubclass(Animal,object) r4 = issubclass(Person,object) r5 = issubclass(int,object) print(r, r1,r3,r4,r5) # True False True True True class Animal: def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') class Dog(Animal): def run(self): print('狗会跑。。。。。') def speak(self): print('汪汪汪汪。。。。。') d = Dog() d.run() # 狗会跑。。。。。
-
二、 方法重写
-
如果在子类有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而非父类的方法,这个特点称之为方法的重写(覆盖,override)
-
当调用一个对象的方法时:
-
会优先去当前对象中寻找是否具有该方法,如有则直接调用
-
如果没有,则去当前对象的父类中寻找,如父类也有则直接调用父类中的方法
-
如还没有,则去父类的父类中寻找,以此类推,直到找到object,如依然没有则报错
-
class Animal: def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') class Dog(Animal): def run(self): print('狗会跑。。。。。') def speak(self): print('汪汪汪汪。。。。。') d = Dog() d.run() # 狗会跑。。。。。 class A(): def test(self): print('A.....') class B(A): pass class C(B): pass c = C() c.test() # A..... class A(): def test(self): print('A.....') class B(A): def test(self): print('B.....') class C(B): pass c = C() c.test() # B..... class A(): def test(self): print('A.....') class B(A): def test(self): print('B.....') class C(B): def test(self): print('C.....') c = C() c.test() # C.....
-
-
三、super()
-
Super() 可以获取到当前类的父类
-
通过super() 返回对象调用父类方法时,不需要传递self
-
# 父类所有的方法(包括特殊方法)都会被子类继承 class Animal: def __init__(self,name): self._name = name def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') @property def name(self): return self._name @name.setter def name(self, name): self._name = name class Dog(Animal): def run(self): print('狗会跑。。。。。') def speak(self): print('汪汪汪汪。。。。。') # d = Dog() # TypeError: __init__() missing 1 required positional argument: 'name' d = Dog('金毛') # 金毛 d = Dog('秋田') # 秋田 print(d.name) class Animal: def __init__(self,name): self._name = name def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') @property def name(self): return self._name @name.setter def name(self, name): self._name = name class Dog(Animal): def __init__(self,name,age): self._name = name self._age = age def run(self): print('狗会跑。。。。。') def speak(self): print('汪汪汪汪。。。。。') @property def age(self): return self._age @age.setter def age(self,age): self._age = age # d = Dog('金毛') # TypeError: __init__() missing 1 required positional argument: 'age' d = Dog('金毛',8) # 金毛 8 print(d.name,d.age) # 如果父类的属性较多 class Animal: def __init__(self,name): self._name = name def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') @property def name(self): return self._name @name.setter def name(self, name): self._name = name class Dog(Animal): # 希望直接调用父类的__init__方法来初始化父类中定义的属性 def __init__(self,name,age): Animal.__init__(self,name) self._age = age def run(self): print('狗会跑。。。。。') def speak(self): print('汪汪汪汪。。。。。') @property def age(self): return self._age @age.setter def age(self,age): self._age = age # d = Dog('金毛') # TypeError: __init__() missing 1 required positional argument: 'age' d = Dog('金毛',8) # 金毛 8 print(d.name,d.age) class Animal: def __init__(self,name): self._name = name def run(self): print('动物会跑。。。。。') def sleep(self): print('动物睡觉。。。。。') @property def name(self): return self._name @name.setter def name(self, name): self._name = name class Dog(Animal): # 希望直接调用父类的__init__方法来初始化父类中定义的属性 # super() 动态获取当前类的父类,通过super()调用父类方法时,不须传入self def __init__(self,name,age): super().__init__(name) self._age = age def run(self): print('狗会跑。。。。。') def speak(self): print('汪汪汪汪。。。。。') @property def age(self): return self._age @age.setter def age(self,age): self._age = age d = Dog('金毛',8) # 金毛 8 print(d.name,d.age)
四、 多重继承
-
在python中是支持多重继承的。可以为一个类同时制定多个父类
-
可以在类名的()中添加多个类,来实现多重继承
-
多重继承,会使子类同时拥有多个父类,并会获取到所有父类的方法
-
在开发中没有特殊情况,应尽量避免使用多重继承,因为多重继承会让我们的代码更加复杂
-
如果多个父类中有同名的方法,则会先在第一个父类中寻找,然后找第二个,第三个。。。前面的会覆盖后面的
-
# __bases__方法,可以获取当前类所有的父类 # python 是支持多重继承的,可以为一个类指定多个父类 class A(): def test(self): print('A.....') class B(): def test(self): print('B.....') class C(B): pass print(C.__bases__) # (<class '__main__.B'>,) print(B.__bases__) # (<class 'object'>,) print(int.__bases__) # (<class 'object'>,) class A(): def test(self): print('A.....') class B(): def test(self): print('B.....') class C(A,B): pass print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>) c = C() c.test() # A..... class A(): pass class B(): def test(self): print('B.....') class C(A,B): pass c = C() c.test() # B.....
五、多态
-
多态是面向对象的三大特性之一
-
一个对象可以以不同的形态去呈现
-
class A: def __init__(self,name): self._name = name @property def name(self): return self._name @name.setter def name(self,name): self._name = name class B: def __init__(self, name): self._name = name @property def name(self): return self._name @name.setter def name(self, name): self._name = name a = A('葫芦娃') b = B('一休哥') def speak(obj): print('你好%s'%obj.name) # speak2() 做了类型检查,只有obj是A类对象的情况,程序才给予执行 # 其他类型的对象,无法使用该函数,这个函数违反了多态 # 违反多态的函数,只适用于一种类型的对象,无法处理其他类型的对象,导致适用性差 def speak2(obj): if isinstance(obj,A): # 只有是A类才行 print('你好%s' % obj.name) speak(a) # 你好葫芦娃 speak(b) # 你好一休哥 speak2(a) # 你好葫芦娃 speak2(b) # 为空 # 对象中有__len__特殊方法就可以使用len()来获取长度 ls = [1,2,3,4,5,6,7] str = 'python' print(len(ls)) # 7 print(len(str)) # 6 class A: def __init__(self,name): self._name = name def __len__(self): return 100 a = A('葫芦娃') print(len(a)) # 100
六、属性和方法
-
属性
-
类属性,直接在类中定义的属性
-
类属性可以通过类或类的实例访问。但是类属性只能通过类对象修改,无法通过实例对象修改
-
class A: # 类属性,直接在类中定义的属性 count = 20 a = A() print(A.count) # 20 print(a.count) # 20 # 类属性无法通过实例对象修改 class A: # 类属性,直接在类中定义的属性 count = 20 a = A() a.count = 0 print(A.count) # 20 这儿依然是20 print(a.count) # 0 # 类属性只能通过类属性修改 class A: # 类属性,直接在类中定义的属性 count = 20 a = A() A.count = 0 print(A.count) # 0 print(a.count) # 0
-
-
实例属性,通过实例对象添加的属性属于实例属性
-
实例属性只能通过实例对象访问和修改,类对象无法访问和修改
-
class A: # 类属性,直接在类中定义的属性 count = 20 def __init__(self): # 实例属性,是通过实例对象添加的属性,self为当前对象,self等同于a self.name = '老大' a = A() print('A',A.name) # AttributeError: type object 'A' has no attribute 'name' print('a',a.name) # a 老大
-
-
-
方法
-
在类中定义,以self为第一个参数的方法都是实例方法
-
实例方法被调用时,python会将调用对象以self传入
-
实例方法可以通过类和类实例去调用
-
当通过实例调用时,会自动将当前调用对象作为 self传入
-
当通过类调用时,不会自动传递self,必须手动传递self
-
class A: # 实例方法 def test(self): print('test。。。') a = A() b = A() a.test() # test。。。 A.test() # TypeError: test() missing 1 required positional argument: 'self' A.test(a) # test。。。 A.test(b) # test。。。
-
-
类方法 以@classmethod 来修饰的方法,第一个参数是cls,cls 是当前类的对象
-
类方法与实例方法的区别,实例方法第一个参数为self,类方法第一个参数为cls
-
类方法可以通过类调用,也可通过实例方法调用
-
class A: count = 0 # 实例方法 def test(self): print('test。。。') # 类方法 @classmethod def test2(cls): print('类方法 test2。。。',cls) a = A() a.test2() # 类方法 test2。。。 <class '__main__.A'> A.test2() # 类方法 test2。。。 <class '__main__.A'> # 类方法可调用类属性 class A: count = 100 # 类方法 @classmethod def test2(cls): print('类方法 test2。。。',cls.count) a = A() a.test2() # 类方法 test2。。。 100 A.test2() # 类方法 test2。。。 100
-
-
-
静态方法
-
在类中用@staticmethod来修饰的方法为静态方法
-
静态方法不需要指定任何的默认参数,静态方法可通过类和实例调用
-
静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
-
静态方法一般都是些工具方法,和当前类无关
-
class A: @staticmethod def test3(): print('静态方法 test3...') a = A() a.test3() # 静态方法 test3... A.test3() # 静态方法 test3...
-
-
七、总结
- 面向对象三大特性:
- 封装 确保对象中数据的安全
- 继承 保证了对象的扩展性
- 多态 保证了程序的灵活性