目录
用于类的函数:
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
封装 enclosure
封装是指隐藏类的实现细节,让使用者不用关心这些细节
封装的目的是让使用者通过尽可能少的方法(或属性)操作对象
私有属性和方法:
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类的私有方法
多态 polymorphic
什么是多态:
字面意思: 多种状态
状态:
静态(编译时状态)
动态(运行时状态)
多态是指在有继承/派生关系的类中,调用基类对象的方法,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态
说明:
多态调用的方法与对象相关,不与类型相关
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()
面向对象的编程语言的特征
封装
继承/派生
多态
多继承 multiple inheritance
多继承是指一个子类继承自两个或两个以上的基类
语法:
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__属性:
作用:
用来记录属性(或方法)的查找顺序
函数重写 overwrite
什么是函数重写
在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)
像内建对象一样进行函数操作
对象转字符串函数:
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)
str(obj) 函数调用方法说明:
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):
...用于添加数据
...
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