封装enclosure
封装是指隐藏类的实现细节,让使用者不关心这些细节
封装的目的是让使用者能过尽可能少的方法或属性操作对象
python的封装是模拟的封装
私有属性和方法:
python类中以双下划线'__' 开头,不以双下划线结尾的标识符为私有成员,私有成员只能使用方法进行访问和修改
两种:
私有属性
私有方法--- 只能让该类的方法来调用
class A: def __init__(self): self.__money = 0 def show_money(self): print("self.__money = ",self.__money) def make_money(self, m): self.__money += m a = A() a.__money = 100 # 修改属性 print(a.__money) # 属性取值 a.show_money() # 0 a.make_money(999) a.show_money() # 999
多态 polymorphic:
字面意思是"多种状态"
多态是指在有继承/派生关系的类中,调用基类的对象的方法,实际能调用子类的覆盖方法的现象叫多态
状态:
静态(编译时状态)
动态(运行时状态)
说明:
python全部对象都只有运行时状态,没有编译时状态
class A: def do(self): print("A") class B(A): def do(self): print("B") class C(B): def do(self): print('C') def work(obj): obj.do() # 请问调用谁? L = [A(), B(), C(), B()] for x in L: work(x)
多继承 multiple inheritance
多继承是指一个子类继承自两个或两个以上的基类
语法:
class 类名(基类名1, 基类名2, ....):
语句块
说明:
一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定
class Plane: def fly(self, height): print("飞机以海拔", height, "米的高度飞行") class Car: def run(self, speed): print("汽车以", speed, 'km/h的速度行驶') class PlaneCar(Plane, Car): '''PlaneCar同时继承自汽车类和飞机类''' pc = PlaneCar() pc.run(300) pc.fly(10000)
多继承的问题(缺陷)
标识符冲突的问题
要谨慎使用多继承
# 小张写了一个类A: class A: def m(self): print("A") # 小李写了一个类B class B: def m(self): print("B") # 小王感觉小张和小李写的类自己可以用 class AB(A, B): pass ab = AB() ab.m() # 调用谁由继承列表中先后顺序来决定
多继承的问题MRO(method resolution order)问题
类的 __mro__属性
用来记录每个类的方法的查找顺序
用MRO来确定钻石继承的方法查找顺序
A
/
B C
/
D
class A: def go(self): print("A") class B(A): def go(self): print("B") super().go() # C class C(A): def go(self): print("C") super().go() # A class D(B, C): def go(self): print('D') super().go() d = D() d.go() # ???
面向对象编程语言特征
封装
继承
多态
面向对象的编程语言:
C++, C#, Python, Java, objective-c, swift, ...
函数(方法)重写
在自定义的类内添加相应的方法,让自定义的类创建的实例像内建对象一样进行内建函数操作
对象转字符串函数的重写(覆盖)
repr(obj) 返回一个符合Python语法规则的字符串:
通常:
eval(repr(obj)) == obj
str(obj) 通过给定的对象返回一个字符串(这个字符串通常是给人阅读的)
说明:
1. str(obj) 函数先查找obj.__str__() 方法,调用此方法并返回结果
2. 如果obj.__str__() 方法不存在,则调用obj.__repr__()方法并返回结果
3. 如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示<__main__.XXX object at 0xAABBCCDD>格式的字符串
# 此示例示意 重写__repr__ 和 __str__方法,实现自定义类的 # 个性化显示 class MyNumber: def __init__(self, value=0): self.data = value def __str__(self): '''此方法必须返回字符串''' print("__str__方法被调用") return "数字:%d" % self.data def __repr__(self): return "MyNumber(%d)" % self.data n1 = MyNumber(100) print("repr(n1)=", repr(n1)) # print("str(n1)=", n1.__str__()) # ??? print("str(n1) =", str(n1)) # 数字: 100 print(n1) # 内部会调用str(n1) n2 = MyNumber(200) print("repr(n2)=", repr(n2)) # repr(n2)-->n2.__repr__()
重载方法:
repr() 函数对应 def __repr__(self):
str() ---------> def __str__(self):
内建函数的重写
__abs__ abs(obj)
__len__ len(obj)
__reversed__ reversed(obj)
__round__ round(obj)
class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __len__(self): '''此函数必须只有一个形参self,此函数必须返回整数''' # return self.data.__len__() return len(self.data) def __repr__(self): return 'MyList(%s)' % self.data def __abs__(self): L = [abs(x) for x in self.data] return MyList(L) # 创建一个新的MyList对象并返回 myl = MyList([1, -2, 3, -4, 5]) print(len(myl)) # myl.__len__() myl2 = abs(myl) # myl.__abs__() print(myl2) # MyList([1, 2, 3, 4, 5])
数据转换函数重写
__complex__ complex(obj)
__int__ int(obj)
__float__ float(obj)
__bool__ bool(obj)
class MyNumber: def __init__(self, value=0): self.data = value def __repr__(self): return "MyNumber(%d)" % self.data def __int__(self): '''此方法必须返回整数''' return int(self.data) n1 = MyNumber(100) x = int(n1) # x = 100 # x = n1.__int__() print(x)
布尔测试函数重写
作用:
用于bool(obj) 函数取值
用于if语句真值表达式取值
用于while 语句真值表达式取值
方法名: __bool__
说明:
当存在__bool__方法时,调用obj.__bool__() 取值
当不存在__bool__方法时,调用obj.__len__() 取值
当再不存在__len__方法时,直接返回True
class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __len__(self): '''返回0为假值,返回非零值为真值''' return len(self.data) def __bool__(self): return all(self.data) myl = MyList([1, -2, 3, -4, 5]) print(myl) print(bool(myl)) # ??? if myl: print("真") else: print("假")
迭代器(高级)
迭代器可以能过next(obj) 函数取值的对象,就是迭代器
迭代器协议:
迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定
迭代器协议的实现方法:
__next__(self)
可迭代对象:
是指能用iter(obj) 函数返回迭代器的对象
可迭代对象的实现方法:
__iter__(self)
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 MyListIterator(self.data) class MyListIterator: 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 # import time myl = MyList([1, -2, 3, -4, 5]) print(sum(myl)) # 3 print(max(myl)) # 5 # it = iter(myl) # it = myl.__iter__() # while True: # try: # x = next(it) # x = it.__next__() # print(x) # time.sleep(1) # except StopIteration: # break for x in myl: print(x) # 1 -2 3 -4 5