python面向对象基础(三)

本节开始,我们将讨论面向对象编程的三大特征:封装、继承和多态。下面,我们将由简至难,依次讨论封装、继承、多态。

一. 封装 enclosure

  • 封装:指隐藏类的实现细节,让使用者不用关心这些细节;
  • 目的:让使用者通过尽可能少的方法(或属性)操作对象;
  • 如何封装:通过私有属性和方法;
  • 私有属性和方法:
  1. 以双下划线'__'开头,不以双下划线结尾的标识符为私有成员;
  2. 私有成员只能用此类的方法进行访问和修改
  • 扩展:了解java的读者可能知道,java中使用了private、default、protected、public关键字,实现了更丰富的封装;
  • 示例:
class A:
    """用私有属性和私有方法封装属性和方法"""
    __dd = 300

    def __init__(self):
        # 创建私有属性,此属性在类外无法访问
        self.__e = 100

    @staticmethod
    # 私有方法
    def __en():
        print('私有方法__en被调用!')

    @classmethod
    def get__dd(cls):
        print("私有的类变量__dd:{}".format(cls.__dd))

    def info(self):
        print('A的实例方法info访问私有属性__e:', self.__e)
        # 调用私有方法
        self.__en()


if __name__ == "__main__":
    a = A()
    a.info()
    a.__class__.get__dd()

    # print(a.__e) #AttributeError: 'A' object has no attribute '__e'
    # print(a.__en()) #AttributeError: 'A' object has no attribute '_en'

    # 创建新变量(属性)
    a.__e = 'hello'
    print(a.__e)
    print(a.__dict__)

运行结果:

   

二. 继承 inheritance 和 派生 derived

  • 什么是继承/派生:
  1. 继承是指从已有的类中派生出新的类,新类具有原类的行为,并能扩展新的行为;
  2. 派生类就是从一个已有的类衍生出新的类,在新的类上可以添加新的属性和行为;
  • 作用:
  1. 用继承派生机制,可以将一些共有功能加在基类中,实现代码共享;(共有的属性和方法向上提,形成抽象)
  2. 在不改变超类的代码基础上改变原有功能
  • 名词:
  1. 基类 base class / 超类 super class / 父类 father class
  2. 派生类 derived class / 子类

1. 单继承

  • 语法:

        class 类名(基类名):
            语句块

  • 说明:单继承是派生类由一个基类衍生而来的
  • 类的__base__属性:用来记录此类的父类
  • 子类对象可以当成父类对象来使用:

       

  • 示例
class Human:
    """此类用来描述人类的共同行为"""
    @staticmethod
    def say(what):
        print('说:', what)

    @staticmethod
    def walk(distance):
        print('走了', distance, '公里')


class Student(Human):
    """描述学生的共同行为"""
    @staticmethod
    def study(subject):
        print('学习', subject)


class Teacher(Student):
    @staticmethod
    def teach(content):
        print('正在教', content)


if __name__ == "__main__":
    h1 = Human()
    h1.say('Today is a good day.')
    h1.walk(5)

    print("#########################")
    s1 = Student()
    s1.say('How are you?')
    s1.walk(5)
    s1.study('Python')

    print("#########################")
    t1 = Teacher()
    t1.say('I am a teacher.')
    t1.walk(3)
    t1.teach('讲解继承派生')
    t1.study('滑冰')

运行结果:

  

2. 覆盖 override

  • 概念:覆盖是指在有继承关系的类中,子类中实现了与父类同名的方法,子类实例调用该方法时,实际调用的是子类中覆盖版本的方法,这种现象被称为覆盖;
  • super 函数:
  1. super(type, obj):返回绑定超类的实例(要求obj必须为type类型的实例);
  2. super():返回绑定超类的实例,等同于super(__class__,实例方法的第一个参数self);
  3. super()必须放在方法内调用
  4. 作用:返回绑定超类的实例,用超类的实例来调用其父类的覆盖方法;
  • 显示调用父类的构造方法:当子类中实现了__init__方法,父类的构造方法并不会被调用,此时需要显示调用父类的构造方法:super().__init__(参数)
  • 示例1:在方法内使用super()
class Human:
    def __init__(self, n, a):
        self.name = n
        self.age = a

    def info(self):
        print('name:', self.name)
        print('age:', self.age)


class Student(Human):
    def __init__(self, n, a, s):
        # 显示调用父类的初始化方法
        super().__init__(n, a)
        self.score = s

    def info(self):
        """# 覆盖,子类只负责干子类的事情"""
        super().info()
        print('score:', self.score)


if __name__ == "__main__":
    h1 = Human('Alex', 22)
    h1.info()

    s1 = Student('Thomas', 25, 99)
    s1.info()

示例2:

class A:
    def work(self):
        print('A.work被调用!')


class B(A):
    """用super构造函数来间接调用父类的覆盖版本的方法"""
    def work(self):
        print('B.work被调用!')

    def super_work(self):
        """此方法先调用一下子类的方法,再调用一下父类的方法"""
        self.work()
        # super().work() #调用父类的work,不能在方法外调用
        # super(B,self).work()
        super(__class__, self).work()


if __name__ == "__main__":
    a = A()
    a.work()

    print("###################")
    b = B()
    b.work()

    # 方法外部,使用super()函数调用B的父类A的work方法
    print("###################")
    super(B, b).work()

    print("###################")
    b.super_work()

示例2运行结果:

  

2. 多继承 multiple inheritance

  • 概念:多继承是指一个子类继承自两个或两个以上的基类;
  • 语法:class类名(基类名1, 基类名2...);
  • 说明:
  1. 一个子类同时继承自多个父类,父类中的方法可以同时被继承下来;
  2. 如果两个父类中有同名的方法,则在子类中又没有覆盖此方法时,调用结果难以确定
  • 问题(缺陷):多继承可能会有标识符(名字空间)冲突的问题;
  • 多继承的MRO(Method Resolution Order)问题:
  1. '类'的__mro__属性:用来记录属性或方法的查找顺序;
  2. 示例:
class A:
    def m(self):
        print('A.m()')


class B:
    def m(self):
        print('B.m()')


class C:
    def m(self):
        print('C.m()')


class D(A, B, C):
    def m(self):
        super(A, self).m()
        super(B, self).m()
        super().m()
        print('D.m()')


if __name__ == "__mian__":
    d = D()
    d.m()
    print(D.__mro__)

运行结果:

结果分析:super()函数根据MRO顺序来查找方法

类D同时继承自类A,B, C,且这些类中都有方法m,在调用super时,方法的查找顺序是按照D.__mro__属性指定的顺序;在D.m()中首先调用的是super(A, self).m(),A的上一个是B,因此首先打印B.m();同理,super(B, self).m(),B的上一个是C,因此打印C.m()。

3. 用于类的函数:issubclass(cls, class_or_tuple)

  • 判断一个类是否继承自其它的类,如果此类是 class 或 tuple 中的一个派生子类,则返回 True ,否则返回 False;
  • 一切类型都是 object 的子类

三. 多态 polymorphic

  • 什么是多态:多态是指在有继承/派生关系的类中,调用“基类对象的方法”,实际能调用子类的覆盖方法,这种现象被称为多态;
  • 说明:
  1. 多态“调用的方法与对象相关”,不与类型相关;
  2. Python全部对象都只有运行时状态(动态),没有'C++语言'里的编译时状态(静态)
  • 示例:
class Shape:
    def draw(self):
        print('Shape的draw()被调用')


class Point(Shape):
    def draw(self):
        print('正在画一个点')


class Circle(Point):
    def draw(self):
        print('正在画一个圆')


def my_draw(s):
    """示意多态的使用"""
    # s.draw调用谁是在运行时由s的类动态决定
    s.draw()


if __name__ == "__main__":
    my_draw(Shape())
    my_draw(Point())
    my_draw(Circle())

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值