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

  示例:
    class A:
        pass
    class B(A):
        pass
    class C(B):
        pass
    issubclass(C, B)  # True
    issubclass(B, A)  # True
    

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

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

示例见:

# enclosure.py

class A:
    def __init__(self):
        self.__p1 = 100  # 私有属性
        print("self.__p1=", self.__p1)

    def __m(self):
        '''这是私有方法,此方法只能用此类的方法来调用,不能在其它地方调用'''
        print("A.__m方法被调用")

    def dowork(self):
        '此方法可以调用私有实例变量和实例方法'
        self.__m()
        print("dowork内.self.__p1=", self.__p1)

class B(A):
    '''此类示意子类不能调用父类的私有成员'''
    def test(self):
        self.__m()  # 出错
        print(self.__p1)  # 出错

a = A()
# print(a.__p1)  # 错误,不允许访问私有属性
# a.__m()  # 无法调用
a.dowork()
# a.test()  # 出错

 


多态 polymorphic
  字面意思: 多种状态
  多态是指在有继承和派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态

  状态:
    静态(编译时确定的状态)
    动态(运行时确定的状态)
  说明:
    多态调用的方法与对象相关,不与类型相关
    python全部对象都只有"动态"没有"C++语言的"编译时状态(静态).
  示例见:

# poly.py


# 此示例示意多态中的动态
class Shape:
    '''此类描述图形类的共有属性和方法'''
    def draw(self):
        print("Shape.draw被调用")
class Point(Shape):  # 点类
    def draw(self):
        print("Point.draw被调用")
class Circle(Point):
    def draw(self):
        print("Circle.draw被调用")

def my_draw(s):
    s.draw()  # 此处显示出多态中的动态

s1 = Circle()
s2 = Point()
my_draw(s2)
my_draw(s1)

 

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

 

多继承 multiple inheritance
  多继承是指一个子类继承自两个或两个以上的父类(基类)

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

  示列见:

# multi_inherit.py

# 此示例示意多继承的语法
class Car:
    def run(self, speed):
        print("汽车以", speed, "km/h的速度行驶")

class Plane:
    def fly(self, height):
        print("飞机以海拔", height, "米高度飞行")

class PlaneCar(Car, Plane):
    """PlaneCar类同时继承自汽车类和飞机类"""


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

 

多继承的问题(缺陷):
  标识符冲突的问题,要谨慎使用多继承
  示例见:

# multi_inherit2.py


# 此示例示意多继承标识符冲突的问题

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

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

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

ab = AB()
ab.m()  # 会???

 

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

# mro.py


# 此示例示意__mro__类属性和用法
class A:
    def go(self):
        print("A")

class B(A):
    def go(self):
        print("B")
        super(B, self).go()  # C

class C(A):
    def go(self):
        print("C")
        super().go()   # A

class D(B, C):
    def go(self):
        print("D")
        super().go()  # B

d = D()
d.go()
    

 


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

  例: s = "I'm a \"Teacher\""
      s1 = str(s)
      print(s1)  # I'm a "Teacher"
      s2 = repr(s)
      print(s2)  # 'I\'m a "Teacher"'
   
函数重写 overwrite
  在自定义的类内加添相应的方法,让自定义的类创建的实例能够像内建对象一样进行内建的函数操作

对象转字符串函数的重写方法:
  repr() 函数的重写方法:
    def __repr__(self):
        ...
  str()  函数的重写方法:
    def __str__(self):
        ...
说明:
  1. str(obj) 函数先查找obj.__str__()方法,调用此方法并返回结果
  2. 如果obj.__str__()方法不存在,则调用obj.__repr__() 方法 并返回结果
  3. 如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示<__main__.xxxxobject at 0xXXXXXXXX> 格式的字符串
示例见:
  

# mynumber.py


class MyNumber(object):
    '''此类用于定义一个自定义的数字类型'''
    def __init__(self, value):
        self.data = value  # data数据

    def __str__(self):
        '''重写object类中的__str__(obj)'''
        print("MyNumber.__str__被调用")
        # return super().__str__()
        return "数字%d" % self.data

n1 = MyNumber(100)
s1 = str(n1)  # s1 = n1.__str__()
print(s1)
n2 = MyNumber(200)
print(str(n2))  # 数字200

# s2 = repr(n1)
# print(s2)
# mynumber2.py


class MyNumber(object):
    '''此类用于定义一个自定义的数字类型'''
    def __init__(self, value):
        self.data = value  # data数据

    def __str__(self):
        '''重写object类中的__str__(obj)'''
        print("MyNumber.__str__被调用")
        return "数字%d" % self.data

    def __repr__(self):
        return "MyNumber(%d)" % self.data

n1 = MyNumber(100)
s1 = str(n1)  # s1 = n1.__str__()
print(s1)

s2 = repr(n1)  # s2 = n1.__repr__()
print(s2)

 


内建函数重写:
   方法名
  __abs__        abs(obj) 函数调用
  __len__        len(obj) 函数调用
  __reversed__   reversed(obj) 函数调用
  __round__      round(obj)  函数调用

 示例见:

# mylist.py

class MyList:
    '''创建一个自定义列表类,
    此MyList内部用列表来存储信息'''
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

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

    def __len__(self):
        '''方法必须反回整数'''
        return self.data.__len__()
        # return len(self.data)

    def __abs__(self):
        '''此方法实现把self的所有元素取绝对
        值后返回全为正数的自定义列表MyList'''
        lst = [abs(x) for x in self.data]
        L = MyList(lst)  # 创建新的MyList
        return L

myl = MyList([1, -2, 3, -4])
print(myl)
print("myl 的长度是:", len(myl))  # myl.__len__()

myL3 = abs(myl)
print(myL3)  # MyList([1, 2, 3, 4])


# myl2 = MyList()
# print(myl2)

 

数值转换函数重写
__complex__      complex(obj) 函数调用
__int__          int(obj) 
__float__        float(obj)
__bool__         bool(obj)

示例见:

# myinteger.py

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

    def __int__(self):
        '''此方法必须返回整数'''
        return self.data

    def __float__(self):
        return float(self.data)

a1 = MyInteger("100")
i = int(a1)  # 将MyInteger类型转为整数
print(i)

f = float(a1)  # a1.__float__()
print(f)

c = complex(a1)  # a1.__complex__()
print(c)

b = bool(a1)  # a1.__bool__()
print(b)

 

布尔测试函数重写
  方法名:  __bool__
  作用:
    用于bool(obj)函数取值
    用于 if 语句的真值表达式
    用于while语句的真值表达式
  说明:
    1. 类内有__bool__(self) 方法,调用obj.__bool__方法取值
    2. 当不存在__bool__(self) 方法,将用obj.__len__() 方法的返回值求布尔值
    3.如果不存在__len__(self) 方法,则直接返回True
  示例见:

# bool.py


class A:
    # def __bool__(self):
    #     print("__bool__方法被调用")
    #     return False
    def __len__(self):
        print('__len__方法被调用')
        return 5
a = A()

print(bool(a))  # False
if a:
    print("a为真值")
else:
    print('a为假值')

 

 

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

什么是可迭代对象
  是指能用iter(obj) 函数返回迭代器的对象(实例)
  可迭代对象的实现方法:
    def __iter__(self):
        ...
        return 迭代器

  示例见:
 

# myiterator.py

# 此示例示意将自定义的类定义为可迭代对象
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

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

    def __iter__(self):
        '''要求此方法必须返回迭代器'''
        return MyList_Iterator(self.data) # 返回迭代器

class MyList_Iterator:
    '此类用来创建能访问MyList类型对象的迭代器'
    def __init__(self, data):
        # 绑定可迭代对象的数据
        self.data = data
        self.cur_index = 0  # 设置迭代器的起始位置
    def __next__(self):
        '''此方法用来实现迭代器协议'''
        if self.cur_index >= len(self.data):
            raise StopIteration
        # 拿到当前索引指向的数
        r = self.data[self.cur_index]
        # 将索引数指向下一个数
        self.cur_index += 1
        return r  # 返回当前的数

L = MyList("ABCD")
print(L)
for x in L:
    print(x)

# it = iter(L)  # it = L.__iter__()
# while True:
#     x = next(it)  # x = it.__next__()
#     print(x)

 


练习:


  3. 写一个类,Fibonacci实现迭代器协议,此类的对象可以作为可迭代对象生成相应的斐波那契数
    1 1 2 3 5 8 13 ....
    如:
        class Fibonacci:
            def __init__(self, n):
                ...
            ....
    实现如下操作:
        for x in Fibonacci(5)
            print(x)  # 1 1 2 3 5
        L = [x for x in Fibonacci(50)]
        print(L)
        pring(sum(Fibonacci(100)))

class Fibonacci:
    def __init__(self, n):
        self.count = n

    def __iter__(self):
        return Fitreror(self.count)


class Fitreror:
    def __init__(self, n):
        '''由迭代器来生成fibonaci数'''
        self.count = n
        self.a = 0
        self.b = 1
        self.cur_count = 0  # 当前生成个数

    def __next__(self):
        if self.cur_count >= self.count:
            raise StopIteration
        v = self.a+self.b
        self.a, self.b = self.b, self.a+self.b
        self.cur_count += 1
        return v


for x in Fibonacci(5):
    print(x)