1.提高了代码的复用性 2.让类与类之间产生了关系,有了这个关系,才有了多态 继承是面向对象的三大特性之一
如建立如下的class:
class Person(): name = '' age = '' class Doctor(): name = '' age = '' def study(self): print('治疗病人') class Soldier(): name = '' age = '' def study(self): print('保卫国家')在上述代码中,person、docter、soldier都具有相同的属性name、age但是在定义的时候每一个都重新定义了一次这样显得代码冗长,且复用性差,所以可以采用继承的方式来进行代码优化。 在定义类时,可以在类名后面加上括号,括号内中指定的是当前类的父类(超类、基类、super)
class Person: def __init__(self,name,age): self.name = name self.age = age class Docter(Person): def study(self): print(f'{self.name}是医生,他的职责是治疗病人') class Soldier(Person): def study(self): print(f'{self.name}是军人,他的职责是保卫国家')调用上述代码:
p1 = Docter('张三', 23) p1.study() p2 = Soldier('李四', 22) p2.study() >>> 张三是医生,他的职责是治疗病人 >>> 李四是军人,他的职责是保卫国家如果在创建类的时候省略了父类,则默认父类是object object是所有类的父类,所有类都继承object
小练习:
# 定义一个动物类 class Animal: def run(self): print('动物跑....') def sleep(self): print('动物睡觉...') # 要定义一个狗类 # 1.直接修改动物类 - 修改起来比较麻烦,会违反ocp元组 # 2.直接创建一个新的类(狗类) - 新类比较麻烦,使用大量的复制粘贴,会出现大量的重复性代码 # 3.直接从Animal类中继承它的属性和方法 class Dog(Animal): def home(self): print('狗看家') #调用一下: dog = Dog() dog.run() dog.sleep() dog.home() # >>>动物跑.... # >>>动物睡觉... # >>>狗看家 # 如果在Dog类中重新定义了run()方法和sleep()方法,则将会覆盖掉父类中的方法,将不再继承父类中的方法如: class Dog0(Animal): def run(self): print('狗跑....') def sleep(self): print('狗睡觉...') dog1 = Dog0() dog1.run() dog1.sleep() # >>> 狗跑.... # >>> 狗睡觉...isinstance()检查一个实例是不是属于一个类
print(isinstance(dog,Dog0)) print(isinstance(dog,Dog)) print(isinstance(dog,Animal)) # >>> False # >>> True # >>> Trueissubclass() # 检查一个类是不是另一个类的子类
print(issubclass(Dog,Animal)) print(issubclass(Dog,object)) print(issubclass(Animal,object)) print(issubclass(Person,object)) # >>> True # >>> True # >>> True # >>> True如果在子类中有和父类重名的方法,通过子类的实例去调用方法时, 会调用子类的方法而不是父类的方法,这个特点称之为方法的重写(覆盖 override)
class A(object): 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....当我们去调用一个对象的时候 会优先去当前对象寻找是否就有该方法,如果有直接调用 如果没有,则去当前对象的父类中去寻找,如果有直接调用父类中的方法 如果没有, 则去父类中的父类寻找,如果有直接调用,以此类推,指导找到object,如果依然没有就报错
定义一个动物类
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 a =Animal('猴子') a.sleep() # >>> 动物睡觉... a.run() # >>> 动物跑.... print(a.name)#因为@property 已经将name转化为了一个对象不再是一个方法了,所以直接调用,不用加括号 # >>> 猴子 a.name = '犀牛' print(a.name) # >>> 犀牛希望可以直接调用父类的__init__来初始化父类中的属性 super()可以用来获取当前类的父类 并且通过super()返回的对象,调用父类方法时不需要传递self
class Dog(Animal): def __init__(self,name,age): # self._name = name # 希望可以直接调用父类的__init__ super().__init__(name) self._age = age def run(self): print('狗跑....') def sleep(self): print('狗睡觉...') @property def age(self): return self._age @age.setter def age(self,age): self._age = age d = Dog('二哈',10) print(d.name) # >>> 二哈 d.name = '德牧' print(d.name) # >>> 德牧 d.run() # >>> 狗跑....语法: 类名.bases 可以用来获取当前类的所有父类 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
class A(object): def test(self): print('A....') # pass class B(object): def test(self): print('B中的test方法') def test2(self): print('B....') class C(B,A): pass print(C.__bases__) # >>> (<class '__main__.B'>, <class '__main__.A'>) c = C() c.test() # >>> B中的test方法 c.test2() # >>> B....在上例中虽然class C同时继承了A、B的方法,但是在定义的过程中先继承了B类中的方法(B写在前面)此时就近在B中继承方法,如果在B中没有才会向下一个继承的类中寻找对应的方法。如:
class C(A, B): pass print(C.__bases__) c = C() c.test() c.test2()执行结果则为
>>> (<class '__main__.A'>, <class '__main__.B'>) >>> A.... >>> 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 # 定义一个方法 def speak(obj): print('你好 %s'%obj.name) a = A('张三') b = B('李四') speak(a) speak(b) >>> 你好 张三 >>> 你好 李四上述代码可知,定义的A、B两类都可以用speak方法调用实例a、b。同样也可以定义更多的方法来调用实例。而不同的方法调用实例呈现出来的方法也是不一样的,这个就是类的多态性。同样也可以在方法中限制多态性,代码如下:
def speak2(obj): # 类型检查 if isinstance(obj,A): print('你好 %s'%obj.name) speak2(a) # >>> 你好 张三 speak2(b) # >>> (无结果)在该方法中,类被限制,也就是说在该方法只能调用A类的实例,不能调用B。此时就不具备多态了。
在上述输出代码中第一个输出是实例a所继承的类属性。
