目录
- 封装
- 多态
- 多继承
- 继承的MRO问题
- 函数重写
面相对象的编程语言的特征 :
C++ / Java / Python / Swift / c#
特征 :
1.继承
2.封装
3.多态
1. 封装
封装 enclosure :
封装是指隐藏类的实现细节,让使用者不用关心这些细节
封装的目的是让使用者尽可能少的使用实例变量(属性)进行操作
私有属性 :
python类中,以双下划线'__'开头,不以双下划线结尾的标识符为私有成员
在类的外部无法直接访问
eg:
class A :
def __init__(self):
self.__p1 = 100 #__p1为私有属性,在类的外部不可调用
def test(self):
print(self.__p1)
self.__m1()
def __m1(self):
print('我是类内的__m1方法')
a = A()
print(a.__p1) #>>>AttributeError: 'A' object has no attribute '__p1'
a.test() #p1=100 ; 我是类内的__m1方法
a.m1() #>>>AttributeError: 'A' object has no attribute '__m1'
2. 多态
多态 polymorphic :
多态是指在继承/派生关系的类中
调用基类对象的方法,实际能调用子类的覆盖版本方法的现象叫做 多态
说明 :
多态调用的方法与对象相关,不与类型相关
python的全部对象都只有'运行时状态(动态)'
没有'C++/Java'里的'编译时状态(静态)'
eg:
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 的类决定(动态决定)
s1 = Circle()
s2 = Point()
my_draw(s1) #调用Circele里的draw
my_draw(s2) #调用Point里的draw
3. 多继承
!!!尽量少使用多继承(仅 C++ Python 支持)!!!
--------------------------------------------------
多继承 multiple inheritance :
多继承是指一个子类继承自两个或两个以上的基类
语法 :
class 类名(基类名1,基类名2,......):
语句块
说明 :
1.一个子类同时继承自多个父类
父类中的方法可以同时被继承下来
2.如果两个父类中有同名方法
而在子类中又没有覆盖此方法时,调用结果难以确定
多继承的问题(缺陷) :
标识符(名字空间冲突的问题),要谨慎使用多继承
eg:
class Car :
def run(self,speed):
print('以',speed,'km/h速度行驶')
class Plane :
def run(self,speed):
print('飞机以',speed,'km/h速度滑动')
def fly(self,height):
print('飞到了海拔',height,'米')
class PlaneCar(Car,Plane):
''' 同时继承 Car 和 Plane'''
p1 = PlaneCar()
p1.fly(10000) #>>>飞到了海拔 10000 米
p1.run(300)
#此时 p1.run()不能确定调用哪个,以继承列表内顺序为准(Car,Plane)
4. 继承的MRO问题
继承的MRO (Merhod Resolution Order) 问题 :
类内的 __mro__ 属性用来记录继承方法的查找顺序
eg:
class A :
def m(self):
print('A.m')
class B(A):
def m(self):
print('B.m')
super().m()
class C(A):
def m(self):
print('C.m')
class D(B,C):
def m(self):
print('C.m')
super().m()
d = D()
print(D.__mro__)
#>>>(<class '__main__.D'>, <class '__main__.B'>,
<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
d.m() #>>>C.m;B.m;C.m 多继承中 suoper()是按照 __mro_顺序查找
练习 :
''' 已知list列表内没有insert_head方法,写一个自定义的类Mylist
继承自list类,在Mylist类内添加'''
class Mylist(list):
def insert_head(self,value):
'''将value插入到列表的开始处'''
self[:0] = [value]
#self.insert(0,value)
L = Mylist(range(1,5))
print(L)
L.insert_head(0)
print(L)
5. 函数重写
函数重写 override :
重写是在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)
像内建对象一样进行内建的函数操作
对象转字符串的函数重写 :
repr(object) 返回一个能代表此对象的 '表达式字符串',
通常: eval(repr(obj)) == obj
str(obj) 通过给定的对象返回一个字符串
对象转字符串函数重写方法 :
repr() 函数的重写方法 :
def __repr__(self):
return 能表达self内容的字符串,eval()可执行字符串
str()函数的重写方法 :
def __str__(self):
return 人能看懂的字符串
说明 :
1.str(obj)函数优先调用obj.__str__()方法返回字符串
2.如果obj没有__str__()方法,则调用obj.__repr__()方法返回字符串
3.如果obj没有__repr__()方法,则调用object类的__repr__()实例方法
显示<xxxx>格式的字符串
eg:#自定义的类使用内建函数进行操作
class MyNumber:
def __len__(self):
return 100
n1 = MyNumber()
x = len(n1) #相当于调用了 return n1.__len__()
print(x) #>>> 100
eg:示例 repr()和str()
class MyNumber:
def __init__(self,value):
self.data = value
def __str__(self):
return "数字:%d" % self.data
def __repr__(self):
return "Mynumber(%d)" % self.data
n1 = MyNumber(100)
print(str(n1)) #>>>数字:100
print(repr(n1)) #>>>Mynumber(100)
数值转换函数的重写 :
def __complex__(self) complex(obj)函数调用
def __int__(self) int(obj)函数调用
def __float__(self) float(obj)函数调用
def __bool__(self) bool(obj)函数调用
eg:#示例数值转换
class MyNumber:
def __init__(self,v):
self.data = v
def __repr__(self):
return "MyNumber(%d)" % self.data
def __int__(self):
return int(v)
n1 = MyNumber(100)
print(type(n1)) #>>><class '__main__.MyNumber'>
n1 = int(n1) #>>>TypeError
内建函数的重写
__abs__() abs(obj)
__len__() len(obj)
__reversed__() reversed(obj)
__round__() round(obj)
eg:#自定义类MyList 与系统内建类一样,用来保存任意类型数据
class MyList :
def __init__(self, iterator=[]):
self.data = [x for x in iterator]
def __repr__(self):
return "MyList(%r)" % self.data
def __abs__(self):
return MyList((abs(x) for x in self.data))
def __len__(self):
return len(self.data )
myl = MyList([1,-2,3,-4])
print(myl)
print(abs(myl)) #>>>MyList([1, 2, 3, 4])
myl2 = MyList(range(10))
print(myl2)
print('myl2的长度是:',len(L2))
布尔测试函数的重写 :
格式 def __bool__(self):
作用 :
用于bool(obj)函数取值
用于if语句真值表达式中
用于while语句真值表达式中 ...
说明:
1.优先调用__bool__方法取值
2.如果不存在__bool__方法,则用__len__() 方法取值后判断是否为零值
如果不为零返回True,否则返回False
3. 如果再没有__len__方法,则直接返回True
迭代器(高级)
什么是迭代器
可以通过next(it) 函数取值的对象就是迭代器
迭代器协议:
迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIterator来终止迭代的约定
实现方法:
类内需要有 __next__(self) 方法来实现迭代器协议
语法形式:
class MyIterator
def __next__(self) :
迭代器协议的实现
return 数据
什么是可迭代对象
是指能用iter(obj) 函数返回迭代器的对象(实例)
可迭代对象内部一定要定义__iter__(self)方法来返回迭代器
可迭代对象的语法形式:
class MyIterable:
def __iter__(self):
语句块
return 迭代器
eg:
class MyList:
def __init__(self,iterator):
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):
''' 有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)
练习 :
写一个类,Fibonacci 实现迭代器协议,此类的对象可以作为可迭代对象生成相应的斐波那契数
1 1 2 3 5 8 ....
class Fibonacci:
def __init__(self, n):
...
实现如下操作:
for x in Fibonacci(10):
print(x)
L = [ x for x in Fibonacci(30)]
print(sum(Fibonacci(25)))
(需要实现迭代器协议)
提示: 可以用一个类来实现,也可以用两个类实现
class Fibonacci:
def __init__(self, n):
...
def __iter__(self):
....
def __next__(self):
....
class Fibonacci:
def __init__(self, n):
self.__count = n
def __iter__(self):
return FiboIterator(self.__count)
class FiboIterator:
def __init__(self, n):
self.__count = n
self.cur_count = 0
self.a = 0 # 用来保存前第二个数
self.b = 1 # 用来保存前一个数
def __next__(self):
if self.cur_count >= self.__count:
raise StopIteration
self.cur_count += 1 # 生成数加1
self.a, self.b = self.b, self.a + self.b
return self.a
for x in Fibonacci(10):
print(x)
L = [x for x in Fibonacci(30)]
print(L)
print(sum(Fibonacci(25)))
#方法二
class Fibonacci:
def __init__(self, n):
self.__count = n
def __iter__(self):
self.cur_count = 0
self.a = 0 # 用来保存前第二个数
self.b = 1 # 用来保存前一个数
return self
def __next__(self):
if self.cur_count >= self.__count:
raise StopIteration
self.cur_count += 1 # 生成数加1
self.a, self.b = self.b, self.a + self.b
return self.a
for x in Fibonacci(10):
print(x)
L = [x for x in Fibonacci(30)]
print(L)
print(sum(Fibonacci(25)))