大爽Python入门教程 7-4 面向对象编程 封装、继承、多态

大爽Python入门公开课教案 点击查看教程总目录

第二节部分的例子,给人最直观的感受,
就是类能够通过self来实现跨函数(方法)传参。
在参数比较多的情景中,这算是一种比较省事的手段。

实际上,类的真正优点不在于此。
而在于其三大特性:封装、继承、多态。

1 三大特性

封装

封装(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)
指为不同数据类型的实体提供统一的接口。

一个父类可以有多个子类,不同的子类对同一方法,有不同的实现。
这就实现了使用一个接口(方法),实现不同的效果(对于不同的子类)。

多态性一般依赖于继承和重写(见下)。

2 常用补充

重写(Override)

子类重写父类的函数,功能上覆盖掉父类。

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方法时,
调用的是Childgreet方法,
父类的方法被覆盖掉了,不再执行。

super

子类可以重写父类的方法,也可以直接沿用父类的方法(什么都不写)。

在重写时,常有的情形是,沿用父类的代码,
然后做一点修改(比如增加一些属性之类的)。

在这个时候,我们无法直接使用父类的方法,因为这个方法名已经被子类用了。
这个时候我们尝试用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也可以,但不常用了

3 实例理解

Animal

我们这里以动物为例,
先实现一个一个基础的动物类,作为所有的动物的父类。

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的很多代码可以直接沿用。
  • 添加功能时,只用作一点针对性的修改。
  • 不同的子类有相同的方法名,不用单独区分再处理,直接一起调用,方便。
    同一方法,不同子类可以有不同实现,最后效果也不同。

4 isinstance 和 type 解析

之前讲过,判断对象类比,一般推荐使用isinstance方法。

这里深入讲一下isinstancetype的区别。

isinstance

先看一下isinstance的文档说明。
isinstance(object, classinfo)

Return True if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof.
If object is not an object of the given type, the function always returns False. >

如果参数 object 是参数 classinfo 的实例或者是其 (直接、间接或 虚拟) 子类的实例,则返回 True。
如果 object 不是给定类型的对象,函数将总是返回 False。

简单来讲,isinstance函数判断object是否是classinfo类或其子类的实例。

比如下面的代码

class A:
    pass


class B(A):
    pass


a = A()
b = B()

r1 = isinstance(a, A)
r2 = isinstance(a, B)
r3 = isinstance(b, A)
r4 = isinstance(b, B)
print(r1)
print(r2)
print(r3)
print(r4)

输出为

True
False
True
True

type

type实际不是一个函数,而是一个类。

其文档说明为
class type(object)

With one argument, return the type of an object.
The return value is a type object and generally the same object as returned by object.class.

传入一个参数时,返回 object 的类型。
返回值是一个 type 对象,通常与 object.class 所返回的对象相同。

简单来讲,type只能用来获取object的类型,无法知道其父类子类之类的关系。

比如下面的代码

class A:
    pass


class B(A):
    pass


a = A()
b = B()
ta = type(a)
tb = type(b)

print(ta)
print(tb)
print(ta==tb)
print(ta==A)
print(ta==B)
print(tb==A)
print(tb==B)

输出为

<class '__main__.A'>
<class '__main__.B'>
False
True
False
False
True
posted @ 2021-12-27 23:20  大爽歌python编程辅导  阅读(166)  评论(0编辑  收藏  举报