python 多态、多继承、函数重写、迭代器

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

判断一个类是否继承自其他的类,如果此类cls是class或tuole中的一个派生(子类)则返回True,否则返回False

封装 enclosure

封装的目的是让使用者尽可能少的引用实例变量(属性)进行操作

私有属性:python类中,以双下划线‘__’开头,不以双下划线结尾的标识符为私有成员,在类的外部无法直接访问。

 1 class A:
 2     def __init__(self):
 3         self.__p1 = 100  #__p1为私有属性,在类的外部不可访问
 4 
 5     def test(self):
 6         print(self.__p1)  # 可以访问
 7         self.__m1()  # A类的方法可以调用A类的私有方法
 8 
 9     def __m1(self):
10         '''我是私有方法,只有我自己的类中的方法才能调用我哦'''
11         print("我是A类的__m1方法!")
12 
13 a = A()  # 创建对象
14 # print(a.__p1)  # 在类外看不到__p1属性,访问失败!
15 a.test()
16 # a.__m1()  # 出错.无法调用私有方法
__私有属性

多态 polymorphic

多态是指在继承\派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖版本方法的现象叫多态

 1 class Shape:
 2     def draw(self):
 3         print("Shape.draw被调用")
 4 
 5 class Point(Shape)
 6     def draw(self):
 7         print('正在画一个点')
 8 
 9 class Circle(Point):
10     def draw(self):
11         print("正在画一个圆")
12 
13 def my_draw(s):
14     s.draw()  # 此处显示出多态中的动态
15 
16 s1 = Circle()
17 s2 = Point()
18 my_draw(s1)  # 调用Circle里的draw 正在画一个圆
19 my_draw(s2)  # 调用Point里的draw 正在画一个点
多态

多继承 multiple inheritance

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

说明:一个子类可以同时继承自多个父类,父类中的方法可以同时被继承下来。如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定

 1 class Car:
 2     def run(self, speed):
 3         print("汽车以", speed, '公里/小时的速度行驶')
 4 
 5 class Plane:
 6     def fly(self, height):
 7         print("飞机以海拔", height, '的高度飞行')
 8 
 9 class PlaneCar(Car, Plane):
10     '''PlaneCar同时继承自汽车类和飞机类'''
11 
12 p1 = PlaneCar()
13 p1.fly(10000)
14 p1.run(300)
多继承

多继承的问题(缺陷):名字冲突问题,要谨慎使用多继承(会先使用第一个继承的基类

 1 class A:
 2     def m(self):
 3         print("A.m()被调用")
 4 
 5 class B:
 6     def m(self):
 7         print('B.m()被调用')
 8 
 9 class AB(A, B):
10     pass
11 
12 ab = AB()
13 ab.m()  # A.m()被调用
命名冲突

继承的MRO(Method Resolution Order)问题

  的__mro__属性用来记录继承方法的查找顺序

 1 class A:
 2     def m(self):
 3         print("A.m")
 4 class B(A):
 5     def m(self):
 6         print("B.m")
 7 class C(A):
 8     def m(self):
 9         print("C.m")
10 class D(B, C):
11     '''d类继承自B,C'''
12     def m(self):
13         print("D.m")
14 d = D()
15 print(D.__mro__)
16 #(<class '__main__.D'>, 
17 # <class '__main__.B'>, 
18 # <class '__main__.C'>, 
19 # <class '__main__.A'>, 
20 # <class 'object'>)
21 d.m()  # 调用方法的顺序如上所示
多继承顺序
 1 class A:
 2     def m(self):
 3         print("A.m")
 4 class B(A):
 5     def m(self):
 6         print("B.m")
 7         super().m()
 8 class C(A):
 9     def m(self):
10         print("C.m")
11         super().m()
12 class D(B, C):
13     '''d类继承自B,C'''
14     def m(self):
15         print("D.m")
16         super().m()
17 d = D()
18 d.m()  # 调用方法的顺序是什么?
19 
20 for x in D.__mro__:
21     print(x)
22 
23 
24 # D.m
25 # B.m
26 # C.m
27 # A.m
28 # <class '__main__.D'>
29 # <class '__main__.B'>
30 # <class '__main__.C'>
31 # <class '__main__.A'>
32 # <class 'object'>
多继承顺序

函数重写

在自定义类内添加相应的方法,让自定义类创建的实例能像内建对象一样进行内建函数操作

对象转字符串函数:

  repr(obj) 返回一个能代表此对象的表达式字符串,通常eval(repr(obj))==obj (这个字符串通常是给python解释执行器运行用的)

对象转字符串函数的重写方法

  reper(obj)函数的重写方法:  def__repr__(self):

                    return 能够表达self内容的字符串

  str(obj)函数的重写方法:  def__str__(self):

                    return 人能看懂的字符串

 1 class MyNumber:
 2     def __init__(self, value):
 3         self.data = value
 4     def __str__(self):
 5         print("__str__被调用")
 6         return "数字: %d" % self.data
 7     def __repr__(self):
 8         print("__repr__被调用")
 9         return 'MyNumber(%d)' % self.data
10 n1 = MyNumber(100)
11 # print(str(n1))  # 调用 n1.__str__(self);__str__被调用;数字: 100
12 # print(repr(n1)) #__repr__被调用  MyNumber(100)
13 print(n1)   # ;__str__被调用;数字: 100
14 # n2 = eval("MyNumber(100)")
15 # print(n2)   #__str__被调用;数字: 100
重写方法

说明:

1、str(obj)函数先调用obj.__str__()方法,调用此方法并返回字符串

2、如果obj没有__str__()方法,则调用obj.__repr__()方法返回的字符串

3、如果obj没有__repr__()方法,则调用object类的__repe__()实例方法显示<xxxx>格式的字符串

数值转换函数的重写

  def __complex__(self)  complex(obj) 函数调用
  def __int__(self)    int(obj) 函数调用
  def __float__(self)   float(obj) 函数调用
  def __bool__(self)    bool(obj) 函数调用

 1 '''此示例示意自定义的类MyNumber能够转成为数值类型'''
 2 class MyNumber:
 3     def __init__(self, v):
 4         self.data = v
 5     def __repr__(self):
 6         return "MyNumber(%d)" % self.data
 7     def __int__(self):
 8         '''此方法用于int(obj) 函数重载,必须返回整数
 9         此方法通常用于制订自义定对象如何转为整数的规则
10         '''
11         return 10000
12 
13 n1 = MyNumber(100)
14 print(type(n1))
15 # if n1 == 100:
16 #     print("n1 == 100")
17 n  = int(n1)
18 print(type(n))
19 print(n)
自定义类可以转成数值类型
1 <class '__main__.MyNumber'>
2 <class 'int'>
3 10000
结果

内建函数的重写
  __abs__      abs(obj)
  __len__      len(obj)
  __reversed__   reversed(obj)
  __round__     round(obj)

 1 # 自定义一个MyList类,与系统内建的类一样,
 2 # 用来保存有先后顺序关系的数据
 3 
 4 class MyList:
 5     '''自定义列表类'''
 6     def __init__(self, iterator=[]):
 7         self.data = [x for x in iterator]
 8 
 9     def __repr__(self):
10         return "MyList(%r)" % self.data
11 
12     def __abs__(self):
13         # return MyList([abs(x) for x in self.data])
14         # 上一句语句可以用如下生成表达式代替已防止过多占内存
15         return MyList((abs(x) for x in self.data))
16 
17     def __len__(self):
18         # return self.data.__len__()
19         return len(self.data)
20 
21 myl = MyList([1, -2, 3, -4])
22 print(myl)
23 print(abs(myl))  # MyList([1, +2, 3, +4])
24 print("原来的列表是:", myl)
25 
26 myl2 = MyList(range(10))
27 print(myl2)
28 print('myl2的长度是:', len(myl2))
29 print('myl的长度是: ', len(myl))
View Code
1 MyList([1, -2, 3, -4])
2 MyList([1, 2, 3, 4])
3 原来的列表是: MyList([1, -2, 3, -4])
4 MyList([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
5 myl2的长度是: 10
6 myl的长度是:  4
结果

 布尔测试函数的重写

  格式 def __bool__(self):
    ...
作用:
  用于bool(obj) 函数取值
  用于if语句真值表达式中
  用于while语句真值表达式中
说明:
  1. 优先调用__bool__方法取值
  2. 如果不存在__bool__方激动 ,则用__len__()方法取值后判断是否为零值,如果不为零返回True,否则返回False
  3. 如果再没有__len__方法,则直接返回True

 1 class MyList:
 2     '''自定义列表类'''
 3     def __init__(self, iterator=[]):
 4         self.data = [x for x in iterator]
 5 
 6     def __repr__(self):
 7         return "MyList(%r)" % self.data
 8 
 9     def __bool__(self):
10         print("__bool__方法被调用!")
11         return False
12 
13     # def __len__(self):
14     #     print("__len__被调用")
15     #     return len(self.data)
16 
17 myl = MyList([1, -2, 3, -4])
18 print(bool(myl))  # False
19 if myl:
20     print("myl 是真值")
21 else:
22     print("myl 是假值")
View Code
1 __bool__方法被调用!
2 False
3 __bool__方法被调用!
4 myl 是假值
结果

 迭代器(高级)

可以通过next(it) 函数取值的对象就是迭代器
迭代器协议:迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIterator来终止迭代的约定
实现方法:类内需要有 __next__(self) 方法来实现迭代器协议
语法形式:
  class MyIterator
    def __next__(self):
      迭代器协议的实现
      return 数据

可迭代对象是指能用iter(obj) 函数返回迭代器的对象(实例),可迭代对象内部一定要定义__iter__(self)方法来返回迭代器

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

# 此示例示意可迭代对象和迭代器的定义及使用方式:
class MyList:
    def __init__(self, iterator):
        '''自定义列表类的初始化方法,此方法创建一个data实例
        变量来绑定一个用来存储数据的列表'''
        self.data = list(iterator)

    def __repr__(self):
        '''此方法了为打印此列表的数据'''
        return 'MyList(%r)' % self.data

    def __iter__(self):
        '''有此方法就是可迭代对象,但要求必须返回迭代器'''
        print("__iter__方法被调用!")
        return MyListIterator(self.data)

class MyListIterator:
    '''此类用来创建一个迭代器对象,用此迭代器对象可以迭代访问
    MyList类型的数据'''
    def __init__(self, iter_data):
        self.cur = 0  # 设置迭代器的初始值为0代表列表下标
        # it_data 绑定要迭代的列表
        self.it_data = iter_data

    def __next__(self):
        '''有此方法的对象才叫迭代器,
        此方法一定要实现迭代器协议'''
        print("__next__方法被调用!")
        # 如果self.cur已经超出了列表的索引范围就报迭代结束
        if self.cur >= len(self.it_data):
            raise StopIteration
        # 否则尚未迭代完成,需要返回数据
        r = self.it_data[self.cur]  # 拿到要送回去的数
        self.cur += 1  # 将当前值向后移动一个单位
        return r

myl = MyList([2, 3, 5, 7])
print(myl)

for x in myl:
    print(x)  # 此处可以这样做吗?

# it = iter(myl)
# x = next(it)
# print(x)
# x = next(it)
# print(x)
# x = next(it)
# print(x)
1 MyList([2, 3, 5, 7])
 2 __iter__方法被调用!
 3 __next__方法被调用!
 4 2
 5 __next__方法被调用!
 6 3
 7 __next__方法被调用!
 8 5
 9 __next__方法被调用!
10 7
11 __next__方法被调用!
结果

 

posted @ 2018-07-26 18:09  凌逆战  阅读(603)  评论(0编辑  收藏  举报