目录
封装 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封装是指隐藏类的实现细节,让使用者不用关心这些细节 封装的目的是让使用者通过尽可能少的方法(或属性)操作对象
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类的私有方法什么是多态: 字面意思: 多种状态
状态: 静态(编译时状态) 动态(运行时状态)
多态是指在有继承/派生关系的类中,调用基类对象的方法,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态 说明: 多态调用的方法与对象相关,不与类型相关 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()面向对象的编程语言的特征 封装 继承/派生 多态
多继承是指一个子类继承自两个或两个以上的基类
语法: 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__属性: 作用: 用来记录属性(或方法)的查找顺序
什么是函数重写 在自定义的类内添加相应的方法,让自定义的类生成的对象(实例) 像内建对象一样进行函数操作
对象转字符串函数: 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)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): ...用于添加数据 ...
class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def append(self, v): self.data.append(v) # ...用于添加数据 def __repr__(self): return 'MyList(%r)' % self.data def __iter__(self): return MyIterator(self.data) def __len__(self): return len(self.data) # self.data.__len__() class MyIterator: def __init__(self, lst): self.data = lst # 绑定要迭代的列表 self.index = 0 # 迭代的起始位置 def __next__(self): if self.index >= len(self.data): raise StopIteration # 发送迭代结束通知 r = self.data[self.index] self.index += 1 return r # 返回此次提供的数据 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 class MyList: class MyIterator: def __init__(self, lst): self.data = lst # 绑定要迭代的列表 self.index = 0 # 迭代的起始位置 def __next__(self): if self.index >= len(self.data): raise StopIteration # 发送迭代结束通知 r = self.data[self.index] self.index += 1 return r # 返回此次提供的数据 def __init__(self, iterable=()): self.data = [x for x in iterable] def append(self, v): self.data.append(v) # ...用于添加数据 def __repr__(self): return 'MyList(%r)' % self.data def __iter__(self): return MyList.MyIterator(self.data) def __len__(self): return len(self.data) # self.data.__len__() 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