轻松学会python面向对象第12篇---重写,儿大不由爷

python面向对象-重写
常言道,儿大不由爷,女大不由娘,讲的是孩子们长大了,有了自己的主意,不再对父母言听计从。在python面向对象的世界里,也存在同样的情形,子类对从父类那里继承来的方法感到不满,想要活出不一样的人生,这就用到重写。

1. 什么是重写

class Dog():
    def __init__(self, _name, _age):
        self.name = _name
        self.age = _age

    def eat_moon(self):
        print("天狗吃月")


class HuntDog(Dog):
    pass

这是前面文章里举的例子,子类HuntDog类在定义时,什么代码都没写,属性与方法都是从父类那里继承来的。你可能对这种形式嗤之以鼻,这样的话,要HuntDog类有什么用。

别急,写这个例子的时候,只是为了让你明白什么是继承,并没有系统性的阐述什么是继承,以及继承的意义。接下来,我就重写父类的eat_monn方法。

class HuntDog(Dog):
    def eat_moon(self):
        print("猎狗不吃月亮,猎狗想吃兔子")


hunt_dog = HuntDog('小黑', 3)
hunt_dog.eat_moon()

去掉HuntDog类里的eat_moon方法,执行hunt_dog.eat_moon()这行代码时,调用的就是父类里定义的eat_moon方法。

现在,子类HuntDog也定义了eat_moon方法,和父类里定义的一模一样,方法名相同,参数也相同,这就是重写,HuntDog类重写了eat_moon方法。此时,执行hunt_dog.eat_moon()这行代码时,调用的就是子类里自己的eat_moon方法。

子类重写了父类的方法,子类所创建的对象实例在调用该方法时,优先调用子类重写后逇方法。

2. 讨论一下父类存在的意义

延续我前面所制定的原则,如果你对于一项技术存在的意义,价值和使用方法感到困惑,不要急于否定它。

面向对象说简单也简单,说复杂也复杂,面向对象的机制和规则,只有在具体的项目实践里才能体现出其优秀的设计思想和作用。在没有机会具体实践的情况下,请先机械的记忆它,接受它,把理解它放在将来的项目实践里。

2.1 父类可以管理共用的代码

为啥要有父类,因为有些代码,完全是共用的,那么把共用的代码放在父类里,子类通过继承来获得这部分代码所实现的功能,就达到了管理代码,管理工程的目的。

某一天,你想修改这部分公共代码时,只需要在父类里修改就可以了,如果共用的代码,每个类都写一份,浪费时间不说,修改起来也是一件麻烦的事情。需求变更,代码重构,修复bug,这些永远不能避免的事情,要求你用一种合理的方法来管理你的代码和工程,否则,你可能会为了一次需求变更而累到怀疑人生。

共用的代码,未必是所有子类都能共用,可能是10个子类里,有7个可以共用,剩下3个,需要有自己独特的实现,需要子类重写父类的方法。

2.2 你和大家不一样,但是别制造麻烦

聪明的你又会问了,既然这3个子类有自己独特的实现,为什么不另外写新的方法呢,非得和父类的方法一样么?

这个问题就又深奥了,它涉及到了设计模式,同样和代码维护成本有关。假设某一处代码是这样写的

dog.eat_moon()

如果使用重写技术,我们就不必去关心这个dog对象,究竟是HuntDog类创建的还是HuskyDog类创建的,反正都有eat_monn方法,调用就是了,至于调用后的功能表现,取决于dog的类型。

如果HuntDog类没有重载eat_moon方法,而是新写了一个吃月亮的方法

class HuntDog(Dog):
    def hunt_eat_moon(self):
        print("猎狗不吃月亮,猎狗想吃兔子")

那么,你就不得不修改dog.eat_moon()这行代码

if isinstance(dog, HuntDog):
    dog.hunt_eat_moon()
else:
    dog.eat_moon()

HuntDog类有自己独特的吃月亮的方法,你不用重写这种技术,而是写一个新的吃月亮的方法,那么在代码里,你就不得不去判断dog这个对象,到底是哪个类创建的。

反正每个狗的类都要有一个吃月亮的方法,你和大家不一样,重写不就好了么,为啥非要特立独行,把代码搞的那么复杂呢?

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案