C# 对象作为参数_史上最全 Python 面向对象编程( 三 )


继承
当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(),而被继承的class称为基类、父类或超类(Base class、Super class) 。
比如,我们已经编写了一个名为的class,有一个run()方法可以直接打印:
class Animal(object):def run(self):print 'Animal is running...'
当我们需要编写Dog和Cat类时,就可以直接从类继承:
class Dog(Animal):passclass Cat(Animal):pass
继承有什么好处?最大的好处是子类获得了父类的全部功能 。由于实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:
dog = Dog()dog.run()cat = Cat()cat.run()
当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run() 。这样,我们就获得了继承的另一个好处:多态 。
多态
要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个类型的变量:
def run_twice(animal):animal.run()animal.run()
当我们传入的实例时,()就打印出:
run_twice(Animal())运行结果:Animal is running...Animal is running...
当我们传入Dog的实例时,()就打印出:
run_twice(Dog())运行结果:Dog is running...Dog is running...
当我们传入Cat的实例时,()就打印出:
run_twice(Cat())运行结果:Cat is running...Cat is running...
看上去没啥意思,但是仔细想想,现在,如果我们再定义一个类型,也从派生:
class Tortoise(Animal):def run(self):print 'Tortoise is running slowly...'
当我们调用()时,传入的实例:
run_twice(Tortoise())运行结果:Tortoise is running slowly...Tortoise is running slowly...
你会发现,新增一个的子类,不必对()做任何修改,实际上,任何依赖作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态 。
多态的好处就是,当我们需要传入Dog、Cat、……时,我们只需要接收类型就可以了,因为Dog、Cat、……都是类型,然后,按照类型进行操作即可 。由于类型有run()方法,因此,传入的任意类型,只要是类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
对于一个变量,我们只需要知道它是类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在、Dog、Cat还是对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的 。这就是著名的“开闭”原则:
对扩展开放:允许新增子类;
对修改封闭:不需要修改依赖类型的()等函数 。
总结:继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写;
有了继承,才能有多态 。在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收;
旧的方式定义类允许不从类继承,但这种编程方式已经严重不推荐使用 。任何时候,如果没有合适的类可以继承,就继承自类 。
魔法方法
在上面有提到除了init之外还有iter,的方法,这里就详细说下除了init初始化还有哪些别的方法 。
__init__ :构造函数,在生成对象时调用__del__ :析构函数,释放对象时使用__repr__ :打印,转换__setitem__ :按照索引赋值__getitem__:按照索引获取值__len__:获得长度__cmp__:比较运算__call__:调用__add__:加运算__sub__:减运算__mul__:乘运算__div__:除运算__mod__:求余运算__pow__:幂