类的继承与多态

302 阅读3分钟

写一个父类:

>>> class Animal(object):
...     def run(self):
...             print('animal is running...')

写一个子类Dog继承父类:

>>> class Dog(Animal):
...     pass

写一个子类Cat继承父类:

>>> class Cat(Animal):
...     pass

创建对象并调用方法:

>>> dog = Dog()
>>> dog.run()
animal is running...
>>> cat = Cat()
>>> cat.run()
animal is running...
>>>

以上两个对象都执行了父类的run方法,这就是继承,能够继承父类东西

对子类进行修改和增加方法:

>>> class Dog(Animal):
...     def run(self):
...             print('Dog is running...')
...     def eat(self):
...             print('Eating meat...')
...
>>> dog = Dog()
>>> dog.run()
Dog is running...
>>> dog.eat()
Eating meat...
>>>

以上我们说,子类覆盖了父类的run方法,并且新增了一个eat方法,是对父类的继承和扩展

判断对象是不是某个类的实例:

>>> a = list() #list类型
>>> b = Animal() #Animal类型
>>> c = Dog() #Dog 类型
>>> isinstance(a, list)
True
>>> isinstance(b, Animal)
True
>>> isinstance(c, Dog)
True
>>>

判断一个子类是不是父类型:

>>> isinstance(c, Animal)
True
>>>

以上说明了,子类的对象也是父类类型,也就是说狗是动物,这是成立的。那么反过来是否成立呢

判断父类的对象是不是子类型:

>>> isinstance(b, Dog)
False
>>>

很显然,反过来就不对了,动物是狗,这是不对的。(Dog 可以看成是 Animal,但是Animal不能看成是Dog)

进一步理解多态,我们再写一个方法:

>>> def run_twice(animal):
...     animal.run()
...     animal.run()
...

当我们传Animal()时:

>>> run_twice(Animal())
animal is running...
animal is running...
>>>

当我们传Dog():

>>> run_twice(Dog())
Dog is running...
Dog is running...
>>>

也就是参数animal,我们既可以传Animal() 也可以传Dog()。最终都会执行对应的run方法。 从这里我们可以知道,我们只需知道参数animal的类型,不用关心传的是子类还是父类。如果新增一个子类,只要确保run方法执行正确,不用管代码具体怎么实现。最终都能执行run方法。这就是设计模式中的开闭原则。

开闭原则:1、对扩展是开放的,可以新增很多子类。
         2、对修改是封闭的,不需要修改父类中的方法

静态语言 vs 动态语言

对于静态语言,比如java 传入的对象必须是父类的实例或者子类的实例,否则无法调用run方法 对于动态语言,比如Python 不一定传对应类型的父类或者子类的实例。只要传入的对象有run方法就可以了

下面是python的例子:

>>> class Timer(object):
...     def run(self):
...             print('start...')
...
>>> run_twice(Timer())
start...
start...
>>>

这就是动态语言的“鸭子类型”,只要传进来的对象,看起来像就行了。一个对象只要看起来像鸭子,走起来像鸭子 ,那么它就可以被看作鸭子。

总结:

1、继承,让代码得到复用
2、多态,让代码可扩展性强,可控性好。