大爽Python入门公开课教案 点击查看教程总目录
第二节部分的例子,给人最直观的感受,
就是类能够通过self
来实现跨函数(方法)传参。
在参数比较多的情景中,这算是一种比较省事的手段。
实际上,类的真正优点不在于此。
而在于其三大特性:封装、继承、多态。
封装(encapsulation)
简单的来讲,就是隐藏对象的属性和实现细节,仅对外公开接口。
就像使用手机,我们并不需要知道手机的底层原理,
也不需要知道运行的app的源码,就可以直接使用手机和APP。
这样在开发过程中,
能更轻松地理解类的方法,调用(使用)类的方法,。
继承(inheritance)
如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,
而把A称为“B的父类别”也可以称“A是B的超类”。
继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码。
在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。
另外,为子类追加新的属性和方法也是常见的做法。
比如有一个父类
class Parent: pass
写一个继承它的子类,写法如下
class Child(Person): pass
也就是在类名后加括号,括号里面加父类。
python支持同时继承多个类,
继承多个时,用逗号隔开。
class GrandChild(Person, Child): pass
多态(polymorphism)
指为不同数据类型的实体提供统一的接口。
一个父类可以有多个子类,不同的子类对同一方法,有不同的实现。
这就实现了使用一个接口(方法),实现不同的效果(对于不同的子类)。
多态性一般依赖于继承和重写(见下)。
子类重写父类的函数,功能上覆盖掉父类。
class Parent: def __init__(self, name): self.name = name def greet(self): print("This is %s" % self.name) class Child(Parent): def greet(self): print("Hi, I'm %s" % self.name) p = Parent("Zhang san") c = Child("Li si") p.greet() c.greet()
其输出为
This is Zhang san Hi, I'm Li si
其中Child
类重写了父类的greet
方法。
Child
类创建的实例,其调用greet
方法时,
调用的是Child
的greet
方法,
父类的方法被覆盖掉了,不再执行。
子类可以重写父类的方法,也可以直接沿用父类的方法(什么都不写)。
在重写时,常有的情形是,沿用父类的代码,
然后做一点修改(比如增加一些属性之类的)。
在这个时候,我们无法直接使用父类的方法,因为这个方法名已经被子类用了。
这个时候我们尝试用super
方法来调用父类的方法,执行父类的代码。
比如现有类Animal
如下
class Animal: def __init__(self, name, age): self.name = name self.age = age
我们想要继承这个类,实现一个宠物类Pet
,
这个类要添加一个新的属性owener
,其代码如下
class Pet(Animal): def __init__(self, name, age, owner): super().__init__(name, age) self.owner = owner
其中
super().__init__(name, age)
就是调用了父类Animal
的__init__
方法。
这个也有其他写法(但不常用)
super(Pet, self).__init__(name, age) # 主要是python2用,python3也可以,但不常用了
我们这里以动物为例,
先实现一个一个基础的动物类,作为所有的动物的父类。
class Animal: def __init__(self, name, age): self.name = name self.age = age self.sound = "" def get_name(self): return self.name def show_info(self): print("%s is %s years old" % (self.get_name(), self.age)) def say(self): print("%s say: %s" % (self.get_name(), self.sound))
Dog
, Cat
, Sheep
接下来实现其子类Dog
, Cat
, Sheep
, 代码如下
class Dog(Animal): def __init__(self, name, age): super().__init__(name, age) self.kind = "Dog" self.sound = "Wang wang" def get_name(self): return "%s %s" % (self.kind, self.name) class Cat(Animal): def __init__(self, name, age): super().__init__(name, age) self.kind = "Cat" self.sound = "miao~" def get_name(self): return "%s %s" % (self.kind, self.name) class Sheep(Animal): def __init__(self, name, age): super().__init__(name, age) self.kind = "Sheep" self.sound = "Mie~" def get_name(self): return "%s %s" % (self.kind, self.name)
然后执行以下代码
animals = [ Dog("Duoduo", 10), Cat("Bubu", 12), Sheep("Lili", 15), ] for a in animals: a.show_info() a.say()
输出如下
Dog DuoDuo is 10 years old Dog DuoDuo say: Wang wang Cat Bubu is 12 years old Cat Bubu say: miao~ Sheep Lili is 15 years old Sheep Lili say: Mie~
上面的例子展示了面向对象写法的一些特点,或者说优点。
Animal
的很多代码可以直接沿用。