2018.7.26
day18回顾
对象------------------------->类
实例变量(属性) 类变量
实例方法 类方法(@classmethod)
静态方法 @staticmethod
类内的预制属性:
__doc__ 绑定文档字符串
__base__ 属性 绑定父类
__slots__列表
限定一个类创建的对象只能有固定的属性(对象没有字典__dict__)
继承/派生
一个父类<----->多个子类
一个子类,只有一个父类的继承关系称为单继承
覆盖 overrride
子类要想调用父类中的被覆盖的方法:
super(类,对象)
super()
子类对象重新实现了__init__(self,...) 方法
class B(A):
def __init__(self,aaa):
super().__init__(aaa)
day19
用于类的函数
issubclass(cls,class_or_tuple)
判断一个类是否继承自其它类,如果此cls 是class 或tuple中的一个派生子类,则返回True,否则返回False
示例:
class A:
pass
class B(A):
pass
class C(B):
pass
issubclass(C, B) # True
issubclass(B, C) # False
issubclass(C, (int, str)) # False
issubclass(C, (int, B, str)) # True
封装 enclosure
封装是指隐藏类的实现细节,让使用者不关心这些细节
封装的目的是让使用者通过尽可能少的方法(或属性)操作对象
私有属性和方法
python类中以双下划线('__')开头,不以双下划线结尾的标识符为私有成员,私有成员或只能用类内的方法进行访问和修改
以__开头的实例变量有私有属性
以__开头的方法为私有方法
示例:
class A:
def __init__(self):
self.__p1 = 100 # 私有属性
def show_A(self):
print('self.__p1: ', self.__p1)
self.__m1() # 调用自己的方法
def __m1(self): # 私有方法
print("__m1(self)方法被调用")
a = A()
a.show_A() # a.__p1: 100
# print(a.__p1) # 出错,在类外部不能访问a的私有属性__p1
# a.__m1() # 出错,不能调用私有方法
class B(A):
pass
b = B()
# print(b.__p1) # 出错, 子类对象不能访问父类中的私有成员
# b.__m1() # 出错
多态 polymorphic
什么是多态:
字面意思:多种状态
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用之类的覆盖方法的现象叫多态
状态:
静态(编译时状态)
动态(运行时状态)
说明:
多态调用方法与对象相关,不与类相关
python的全部对象都只有‘运行时状态(动态)’
没有‘c++语言’ 里的 ‘编译时状态(静态)’
示例:
# 此示例示意python中的运行时状态
class Shape:
def draw(self):
print('Shape的draw方法被调用')
class Point(Shape):
def draw(self):
print("正在画一个点")
class Circle(Shape):
def draw(self):
print("正在画一个圆")
def my_draw(s):
s.draw() # 此处调用哪儿方法呢? 此处显示出'动态'
s1 = Circle()
s2 = Point()
my_draw(s2)
my_draw(s1)
面向对象的语言的特征:
继承
封装
多态
多继承 multiple inheritance
多继承是指一个子类继承自两个或两个以上的基类
语法:
class 类名(基类名1,基类名2,...):
...
说明:
1,一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
2,如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定
示例:
# 此示例示意用多继承来派生新类
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)
多继承的问题(缺陷)
标识符(名字空间)冲突的问题
要谨慎使用继承
示例:
# 此示例示意多继承名字冲突问题
# 小张写了一个类A
class A:
def m(self):
print('A.m()被调用')
# 小李写了一个类B
class B:
def m(self):
print('B.m()被调用')
# 小王感觉小张和小李写的两个类自己可以用
class AB(A, B):
pass
ab = AB()
ab.m() # 请问会发生什么?
多继承的MRO(Method Resolution Order) 问题
类的__mro__ 属性
此属性用来记录类的方法查找顺序
示例见:
# mro.py
class A:
def go(self):
print('A')
# super().go() # error
class B(A):
def go(self):
print('B')
super().go()
class C(A):
def go(self):
print('C')
super().go()
class D(B, C):
def go(self):
print('D')
super().go()
d = D()
d.go() #
练习:
写一个类Bicycle类,有run方法,调用时显示骑行里程km
class Bicycle:
def run(self,km):
print('自行车骑行了',km,'公里)
再写一个类EBicycle(电动自行车类),
在Bicycle类的基础上添加了电池电量 volume 属性, 有两个方法:
1, fill_charge(self, vol) 用来充电, vol为电量
2, run(self, km) 方法每骑行10km消耗电量1度,同时显示当前电量,当电量耗尽时调用 父类的run方法继续骑行
b = EBicycle(5) # 新买的电动有内有5度电
b.run(10) # 电动骑行了10km还剩 4 度电
b.run(100) #电动骑行了40km,还剩0度电,其余60用脚登骑行
b.fill_charge(10) # 又充了10度电
b.run(50) # 骑行了50公里剩5度电
解析:
class Bicycle:
def run(self, km):
print('自行车骑行了', km, '公里')
# 1. fill_charge(self, vol) 用来充电, vol为电量
# 2. run(self, km) 方法每骑行10km消耗电量1度,同时显示当前电量,当电量耗尽时调用 父类的run方法继续骑行
class EBicycle(Bicycle):
def __init__(self, vol):
self.volume = vol # 电量
def fill_charge(self, vol):
self.volume += vol
print("电动自行车充电%d度" % vol)
def run(self, km):
# 先算电走的里程,和要行驶的里程,哪儿个最小
e_km = min(km, self.volume * 10) # 电行驶里程
self.volume -= e_km / 10 # 消耗电量
if e_km > 0:
print("电动自行车骑行了", e_km, '公里,剩余电量',
self.volume, '度')
if km > e_km: # 有路程没走完
super().run(km - e_km)
b = EBicycle(5) # 新买的电动有内有5度电
b.run(10) # 电动骑行了10km还剩 4 度电
b.run(100) #电动骑行了40km,还剩0度电,其余60用脚登骑行
b.fill_charge(10) # 又充了10度电
b.run(50) # 骑行了50公里剩5度电
函数重写:
在自定义类内添加相应的方法,让自定义类创建的实例能像内建对象一样进行内建函数操作
对象转字符串函数:
repr(obj) 返回一个能代表此对象的表达式字符串,通常eval(repr(obj))==obj(这个字符串通常是给python解释执行器运行用的)
str(obj) 通过给定的对象返回一个字符串(这个字符串通常是给人阅读的)
对象转字符串函数的重写方法
repr(obj) 函数的重写方法:
def __repr__(self):
str(obj) 函数的重写方法:
def __str__(self):
说明:
1,str(obj) 函数先查找,obj.__str__() 方法,调用此方法并返回结果
2,如果没有obj.__str__()方法时,则返回obj.__repr__() 方法的结果并返回
3,如果obj.__repr__方法不存在,则调用object类的__repr__ 实例方法显示 <__main__.XXXX object at 0xAABBCCDD>格式的字符串
示例:
# 此示例示意通过重写 repr 和 str方法改变转为字符串的规则
class MyNumber:
def __init__(self, value):
'构造函数,初始化MyNumber对象'
self.data = value
def __str__(self):
'''转换为普通人识别的字符串'''
# print("__str__方法被调用!")
return "自定义数字类型对象: %d" % self.data
def __repr__(self):
'''转换为eval能够识别的字符串'''
return 'MyNumber(%d)' % self.data
n1 = MyNumber(100)
n2 = MyNumber(200)
print('repr(n1) ====>', repr(n1))
print('str(n2) ====>', str(n2))
示例2:
# 此示例示意通过重写 repr 和 str方法改变转为字符串的规则
class MyNumber:
def __init__(self, value):
'构造函数,初始化MyNumber对象'
self.data = value
# def __str__(self):
# '''转换为普通人识别的字符串'''
# # print("__str__方法被调用!")
# return "自定义数字类型对象: %d" % self.data
def __repr__(self):
'''转换为eval能够识别的字符串'''
return 'MyNumber(%d)' % self.data
n1 = MyNumber(100)
n2 = MyNumber(200)
print('repr(n1) ====>', repr(n1))
print('str(n2) ====>', str(n2))
其它内建函数的重写方法:
__abs__ abs(obj) 函数
__len__ len(obj) 函数(必须返回整数)
__reversed__ reversed(obj) 函数(必须返回可迭代对象
__round__ round(obj) 函数
示例见:
# 此示例示意abs 函数的重写
class MyInteger:
def __init__(self, v):
self.data = v
def __repr__(self):
return 'MyInteger(%d)' % self.data
def __abs__(self):
v = abs(self.data)
return MyInteger(v) # 用v创建另一个MyInteger对象
def __len__(self):
return 10000
I1 = MyInteger(-10)
print('I1 =', I1)
I2 = abs(I1)
print("I2 =", I2)
print('len(I2)=', len(I2)) # 10000
数值转换函数的重写
__complex__ complex(obj) 函数
__int__ int(obj) 函数
__float__ float(obj) 函数
__bool__ bool(obj)函数
示例:
# 此示例示意数据转换构造函数的重写方法
class MyNumber:
def __init__(self, value):
self.data = value
def __repr__(self):
return 'MyNumber(%d)' % self.data
def __int__(self):
return self.data
n1 = MyNumber(100)
x = int(n1) # 转为整数?
print(x)
print(bool(n1)) # True
n2 = MyNumber(0)
print(bool(n2)) # ????
布尔测试函数重写
格式:
__bool__
作用:
用于bool(obj)函数取值
用于if语句的真值表达式
用于while 语句的真值表达式
说明:
1,当自定义的类有__bool__(self) 方法时,以此方法的返回值作为bool(obj) 的返回值
2,当不存在__bool__(self) 方法时,bool(x) 返回__len__(self) 方法的返回值是否为零来测试布尔值
3,当不存在__len__(self) 方法时,则直接返回True
示例:
# 此示例示意bool(x) 函数的重写
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):
print("__bool__方法调用")
for x in self.data:
if not x:
return False
return True
# return False # <<=== 所有对象都为False
myl = MyList([0, -1, 2, -3])
# myl = MyList()
print(myl)
print(bool(myl))
if myl:
print("myl为真值")
else:
print('myl为假值')
迭代器(高级)
什么是迭代器
可以通过next(it)函数取值的对象就是迭代器
迭代器协议
迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定
迭代器协议实现方法:
__next__(self) 方法来实现迭代器协议
语法形式:
class MyIterator:
def __next__(self):
迭代器协议
return 数据
什么是可迭代对象:
是指能用iter(obj) 函数返回迭代器的对象(实例)
可迭代对象内部需要定义__iter__(self) 方法来返回迭代器对象
# 此示例示意让自定义的作为可迭代对象能让 for 语句迭代访问
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:
'''此类用来创建迭代器,此类型的迭代器可以迭代访问
MyList类型的对象'''
def __init__(self, lst):
self.data = lst
self.cur_index = 0 # 初始化迭代器的起始位置
def __next__(self):
'''此方法用于实现迭代器协议'''
if self.cur_index >= len(self.data):
# 如果索引越界就发终止迭代通知
raise StopIteration
value = self.data[self.cur_index] # 要返回的值
self.cur_index += 1
return value
myl = MyList([0, -1, 2, -3])
print(myl)
# it = iter(myl)
# print(next(it))
for x in myl: # 迭代访问自定义类型的对象
print(x)
练习
1,修改原有的学生信息管理系统,将学生对象的,全部属性都变为私有属性,不让外部直接来实现封装
2,写一个列表类MyList实现存储整数列表,写类的定义如下:
class MyList:
def __init__(self,iterator):
self .data=...
让此类的对象能用for语句进行迭代访问
L = MyList(range(5))
print(L)
L2 = [x ** 2 for x in L]
print(L2) # [0, 1, 4, 9, 16]
3,写一个类Fibonacci 实现迭代器协议,此类的对象可以作为可迭代对象生成相应的斐波那契数1 1 2 3 5
class Fibonacci:
def __init__(self,n):
...
...
实现如下操作:
for x in Fibonacci(10):
print(x) # 1 1 3 5 8 ....
L = [x for x in Fibonacii(50)]
print(L)
F = fibonicci(30)
print(sum(F))
class Fibonacci:
def __init__(self, n): # n代表数据的个数
self.__count = n
def __iter__(self):
self.cur = 0 # 当前已生成的个数
self.a = 0
self.b = 1 # 当前的第一个斐波那契数
return self
def __next__(self):
if self.cur >= self.__count: # 不需要再生成
raise StopIteration
self.cur += 1 # 已生成的个数加1
v = self.b # 绑定当前的数,待返回
# 计算下一个数,待下次返回
self.a, self.b = self.b, self.a + self.b
return v # 把当前值返回
for x in Fibonacci(10):
print(x) # 1 1 3 5 8 ....
L = [x for x in Fibonacci(50)]
print(L)
F = Fibonacci(30)
print(sum(F))
上课期间出去1个多小时,整理不是很完整,如果错误请在文章下面留言哦