(十九)python 封装 多态 多继承 函数重写

目录

封装  enclosure

私有属性和方法:

多态  polymorphic

多继承  multiple inheritance

函数重写  overwrite

    对象转字符串的重写方法

    str(obj) 函数调用方法说明:

    内建函数重写

    数值转换函数重写

    布尔测试函数重写

迭代器(高级)


用于类的函数:
   issubclass(cls,class_or_tuple)
  判断一个类是否继承自其他的类,如果此类cls是class或tuple中的一个派生子类,则返回True,否则返回False

class A:
    pass

class B(A):
    pass

class C(B):
    pass

print(issubclass(C, B)) # True
print(issubclass(B, C))  # False
print(issubclass(bool, (C, B, A, int)))  # True


封装  enclosure

    封装是指隐藏类的实现细节,让使用者不用关心这些细节
    封装的目的是让使用者通过尽可能少的方法(或属性)操作对象

私有属性和方法:

  python类中以双下划线('__')开头,不以双下划线结尾的标识符为私有成员,私有成员只能用此类的方法进行访问和修改

# 此示例示意用私有属性和私有方法来进行封装
class A:
    def __init__(self):
        self.__p1 = 100  # 创建私有属性,此属性在类外无法访问

    def __m1(self):  # 私有方法
        print("__m1 私有方法被调用")

    def infos(self):
        print("A类的infos访问的__p1属性是:", self.__p1)
        self.__m1()  # 调用自己的私有方法
    
a = A()
# print(a.__p1)  # 出错
a.infos()
# a.__m1()  # 当前主模块不能调用A类的私有方法


多态  polymorphic

    什么是多态:
        字面意思: 多种状态

    状态:
        静态(编译时状态)
        动态(运行时状态)

    多态是指在有继承/派生关系的类中,调用基类对象的方法,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态
    说明:
        多态调用的方法与对象相关,不与类型相关
        python全部对象都只有运行时状态(动态)
        没有"c++语言"里编译时状态(静态)

# 此示例示意python的多态(动态)
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.draw调用谁是在运行时由s的类型动态决定
              # 此处显示出运行时状态

shape1 = Circle()
shape2 = Point()
my_draw(shape1)
my_draw(shape2)

L = [Point(), Circle(), Point(), Point(), Circle()]

for s in L:
    s.draw()

面向对象的编程语言的特征
    封装
    继承/派生
    多态

多继承  multiple inheritance

    多继承是指一个子类继承自两个或两个以上的基类

    语法:
        class 类名(基类名1,基类名2,...)
    说明:
        一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
        如果两个父类中有同名的方法,则在子类中又没有覆盖此方法时,
        调用结果难以确定

# 此示例示意多继承的语法和用法
class Car:
    def run(self, speed):
        print('车正在以', speed, '公里/小时的速度行驶')

class Plane:
    def fly(self, height):
        print('飞机以海拔', height, '米的高空飞行')

class PlaneCar(Plane, Car):
    '''PlaneCar类同时继承是Plane和 Car类'''

p1 = PlaneCar()
p1.fly(10000)
p1.run(300)

多继承的问题(缺陷)
    标识符(名字空间)冲突问题
    要谨慎使用多继承

# 小张写了一个类:
class A:
    def m(self):
        print("A.m() 被调用")

# 小李写了一个类B
class B:
    def m(self):
        print("B.m() 被调用")

# 小王感觉小张和小李写的两个类自己可以用
class AB(A, B):
    def m(self):
        print("AB.m() 被调用")
        super().m()
        super(A, self).m()

ab = AB()
ab.m()  # 当AB类没有覆盖父类的方法时会出现名字冲突问题


多继承的MRO(Method Resolution Order)等问题
类的__mro__属性:
    作用:
        用来记录属性(或方法)的查找顺序

函数重写  overwrite

    什么是函数重写
        在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)
        像内建对象一样进行函数操作

    对象转字符串函数:
        repr(x) 返回一个能代表此对象的表达式字符串,通常:
            eval(repr(obj)) = obj
        str(obj) 通过给定对象,返回一个字符串(这个字符串通常是给人阅读的)  


    对象转字符串的重写方法


        repr() 函数的重写方法
            def __repr__(self):
                ...
                return 字符串
        str() 函数的重写方法:
            def __str__(self):
                ...
                return 字符串

# 此示例示意repr函数和str函数的不同
s = "I'm Teacher"
print(str(s))  
print(repr(s))


class MyNumber:
    def __init__(self,value):
        self.data = value
    def __str__(self):
        print("正在调用__str__方法,转换为普通字符串")
        s = "自定义数据%d" % self.data
        return s
  
    def __repr__(self):
        return 'MyNumber(%d)' % self.data

n1 = MyNumber(100)
print(str(n1))
print(repr(n1))
# 此示例示意自定义的对象转为python内键的数字类型
class MyNumber:
    def __init__(self, v):
        self.data = v
    def __repr__(self):
        return "MyNumber(%d)" % self.data
    def __int__(self):
        return int(self.data)

n1 = MyNumber(100.5)
n = int(n1)  # 自定义类型转为整数, 出错!!!
print(n)


    str(obj) 函数调用方法说明:

      1. str(obj) 函数先查找obj.__str__()方法,调用此方法并返回结果
      2. 如果obj.__str__() 方法不存在,则调用obj.__repr__()方法并返回结果
      3. 如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示
        <__main__.MyNumber object at xxx>格式的字符串


    内建函数重写

        __abs__         abs(obj) 函数调用
        __len__         len(obj) 函数调用
        __reversed__   reversed(obj) 函数调用
        __round__       round(obj) 函数调用

# 此示例示意 abs 和len方法的重写方法

class MyInteger:
    def __init__(self, v):
        self.data = v

    def __repr__(self):
        return 'MyInteger(%d)' % self.data

    def __abs__(self):
        '''此方法用于制定abs(obj) 函数取值时返回的结果'''
        if self.data < 0:
            # 用-self.data 创建一个新的对象返回回去
            t = MyInteger(-self.data)
            return t
        return MyInteger(self.data)

i1 = MyInteger(-100)

print(i1)  # 等同于print(str(i1)) 
n = abs(i1)
print(n)  # MyInteger(100)

i2 = MyInteger(200)
print(abs(i2))  # MyInteger(200)


    数值转换函数重写

        __complex__     coplex(obj)  函数调用
        __int__         int(obj)  函数调用
        __float__       float(obj)  函数调用
        __bool__        bool(obj)  函数调用

# 此示例示意自定义的对象转为python内键的数字类型
class MyNumber:
    def __init__(self, v):
        self.data = v
    def __repr__(self):
        return "MyNumber(%d)" % self.data
    def __int__(self):
        return int(self.data)

n1 = MyNumber(100.5)
n = int(n1)  # 自定义类型转为整数, 出错!!!
print(n)

    布尔测试函数重写

        格式:
            def __bool__(self):
                ...
        作用:
        用于bool(obj)函数取值
        用于if语句真值表达式中
        用于while语句的值表达式中

    说明:
        1.当自定义类有__bool__(self)方法时,以此方法的返回值作为bool(obj)的返回值
        2. 当不存在__bool__(self)方法时,bool(x)返回__len__(self)方法的返回值是否为零来测试布尔值
        3.当再不存在__len__(self)方法时,则直接返回True

# 此示例示意__bool__方法的重写方法及用法

class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return "MyList(%s)" % self.data

    def __len__(self):
        print("__len__被调用")
        return len(self.data)
    def __bool__(self):
        '''此方法用来制定一个bool(x) 返回的规则'''
        # 如果没有任何元素返回False
        print("__bool__方法被调用")
        if len(self.data) == 0:
            return False
        for x in self.data:
            if x:
                return True
        return False

myl = MyList([1, -2, 3, -4])
# myl = MyList()
print(myl)
print(bool(myl))  # False
print(len(myl))

myl1 = MyList([0, 0.0, False, None])    
print(bool(myl1))  # False

myl2 = MyList([0, 1, 2])
print(bool(myl2))  # True


迭代器(高级)

    什么是迭代器
       可以通过next函数取值的对象就是迭代器 

    迭代器协议
        迭代器协议是指对象能够使用next函数获取下一个数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定
    迭代器的实现方法:
        __next__(self) 此方法用来实现迭代器协议

    什么是可迭代对象:
        是指能用iter(obj) 函数返回迭代器对象
        可迭代对象内部要定义__iter__(self) 方法来返回迭代器对象

    可迭代对象的语法形式:
       class MyIterable:
           def __iter__(self):
               语句块
               return 迭代器

# 此示例示意用自定义的类MyRange实现可迭代对象
# 用自定义的类MyIterator 实现迭代器

class MyIterator:
    def __init__(self, start, stop, step):
        # self.start变量用来记录迭代器的起始位置和当前位置
        self.start = start
        self.stop = stop
        self.step = step
    def __next__(self):
        '''此方法用于实现迭代器协议'''
        print("MyIterator.__next__方法被调用!")
        if self.start >= self.stop:  # 迭失终止条件
            raise StopIteration
        r = self.start  # 先将要返回的数存于变量r中
        self.start += self.step  # 迭代器后移
        return r  # 送回给next(it) 调用
class MyRange:
    def __init__(self, start, stop=None, step=1):
        if stop is None:
            stop = start
            start = 0
        self.start = start  # 起始值
        self.stop = stop    # 终止值
        self.step = step    # 步长
    def __repr__(self):
        return "MyRange(%d, %d, %d)" % (self.start,
            self.stop, self.step)
    def __iter__(self):
        '''此方法用于把MyRange类型创建的对象当做可迭代对象
        '''
        print("__iter__被调用")
        # 此处必须返回迭代器
        return MyIterator(self.start, self.stop, self.step)

L = [x for x in MyRange(5, 10)]
print(L)
print('----------------------------')
R = MyRange(5, 10, 2)
it = iter(R)  # R.__iter__
print(next(it))  # it.__next__


练习:
  写一个类MyList 实现和list内几乎一样的功能 
    在MyList类内用列表来存储数据 
  如:
    class MyList:
        def __init__(self, iterable=()):
            self.data = [x for x in iterable]
        def append(self, v):
            ...用于添加数据
        ...

    L = MyList("ABCD")
    print(L)  # MyList(['A', 'B', 'C', 'D'])
    L.append('E')
    print(L)  # MyList(['A', 'B', 'C', 'D', 'E'])
    for x in L:
        print(x)  # A B C D E
    print("列表L的长度是:", len(L))  # 5

猜你喜欢

转载自blog.csdn.net/zh__quan/article/details/81608181