在OPP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类。而被继承的class称为基类或父类。
比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接接打印:
class Animals:
def run(self):
print('Animals is running...')
当我们需要编写Dog和Cat类时,可以直接从Animals中继承:
class Dog(Animals):
pass
class Cat(Animals):
pass
dog = Dog()
dog.run()
cat = Cat()
在这里Animals时父类,Cat和Dog就是子类,子类能获取父类的功能。
运行的结果是:
Animals is running...
Animals is running...
当子类和父类都存在相同的方法是时,子类会覆盖父类,这样代码在运行的时候,就会调用子类,这样我们就获得了继承 的另一个好处:多态
类是创建实例的模板,而实例是一个一个具体的对象。各个实例拥有的数据互相独立,互相不影响
方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据
使用isinstance():
获取对象继承关系
使用dir();
获得一个对象的所有属性和方法
在编写程序的时候,千万不要把实例属性和类属性使用相同的名字,因为相同名称的实例属性会屏蔽类属性,但当你删除实例属性后,在使用相同的名称,返回的将会是类属性
多态:
继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树
继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。
案例:
classAnimal(object):
defrun(self):
print('Animal is running...')
classDog(Animal):
defrun(self):
print('Dog is running...')
classCat(Animal):
defrun(self):
print('Cat is running...')
defrun_twice(animal):
animal.run()
animal.run()
a=Animal()
d=Dog()
c=Cat()
print('a is Animal?',isinstance(a, Animal))
print('a is Dog?',isinstance(a, Dog))
print('a is Cat?',isinstance(a, Cat))
print('d is Animal?',isinstance(d, Animal))
print('d is Dog?',isinstance(d, Dog))
print('d is Cat?',isinstance(d, Cat))
run_twice(c)
对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则: