day20
##########################################################
day19回顾
面向对象:
封装:隐藏实现细节,供用户使用的实例方法叫做接口
私有属性/私有方法(以双下划线)
继承:单继承/多继承
多态:python只有动态
多继承:一个类有两个或两个以上的父类
MRO 当实例方法冲突时的执行顺序
类.__mro__ 查询
函数重写:在自定义的类内加入相应的方法,让自定义类型的对象使用
内建函数进行操作
repr 将对象转化为机器阅读的字符串
str
int
float
complex
bool
abs
len
next()
iter()
迭代器: iter(obj) 返回的对象 obj__iter__()返回
next(it) 取值 it_next__() 取值
###########################################################
day20笔记
异常(高级)
with语句
语法:
with 表达式1[as 变量1],表达式2[as 变量2],....:
语句块
作用:
使用于对资源进行访问的场合,确保使用过程不管是否发生异常都会执行
必须的'清理'操作,并释放资源
如: 文件打开后自动关闭,线程中锁的自动获取和释放(线程后面回学)
说明:
as 子句中的变量用于绑定表达式执行后的对象
with 语句并不会改变异常状态
自己创建的类不能用with语句
示例:
with.py
#第一种方式用try_finally保证文件一定能关闭
try:
f = open("'../../day19/day19.txt'")
try:
for l in f:
x = int("aaaaa") # 出现异常
print(l)
finally:
f.close()
print('文件已经关闭')
except OSError:
print("打开文件失败")
#第二种方式用with保证文件一定能关闭
#with语句自动关闭文件,不用手动关闭
#只能是open才能用with语句
try:
with open('../../day19/day19.txt') as f:
for l in f:
x = int('aaa') #当进入异常流程时,打开的文件也能被关闭
print(l)
except OSError:
print("打开文件失败")
环境资源管理器
1.类内有 __enter__和__exit__实例方法的类创建的对象成为环境管理器
2.能够用with语句进行管理的对象必须是环境管理器
3.__enter__方法将在进入with语句时被调用,由as变量绑定返回对象
4.__exit__方法将在离开with语句时自动被调动,且可以通过参数
来判断离开with语句时是否异常发生
示例见:
with2.py
class A:
'''此类的对象可以用于with语句进行管理'''
def __enter__(self):
print('此方法是在with语句内执行的')
return self # self将被with中的as变量绑定
def __exit__(self, exec_type, exc_val, exc_tb):
'''exec_type用来绑定错误类型,当没有异常发生时绑定None
exc_val用来绑定错误对象,当没有异常发生时绑定None
exc_tb用来绑定TrackBack对象,当没有异常发生时绑定None'''
if exec_type is None:
print("您已经离开with语句,离开时没有发生任何异常")
else:
print("您已经离开with语句")
print("错误类型是:", exec_type)
print("错误对象是:", exc_val)
print('TrackBack:', exc_tb)
with A() as a:
print('这是with语句内部的输出')
int(input('请输入整数:'))
print("程序正常结束")
运算符重载
什么事运算符重载
让自定义的类生成对象(实例)能够使用运算符进行操作
作用:
让自定义类的实例像内建对象一样进行运算符操作
让程序简洁易读
让自定义对象将运算符赋予新的规则
算术运算符的重载:
方法名 运算符表达式 说明
__add__(self,rhs) self + rhs 加法
__sub__(self,rhs) self - rhs 减法
__mul__(self,rhs) self * rhs 乘法
__truediv__(self,rhs) self / rhs 除法
__floordiv__(self,rhs) self // rhs 地板除
__mod__(self,rhs) self % rhs 取模(求余)
__pow__(self,rhs) self ** rhs 幂运算
注:rhs (right hand side)即表示右手边的数据
示例见:
mynumber.py
class Mynumber:
def __init__(self, v):
self.data = v # self.data用来保存对象的数据
def __repr__(self):
return 'MyNumber(%d)' % self.data
def __add__(self, other):
'''此方法用于制定self + other 的规则'''
v = self.data + other.data
return Mynumber(v) # 用v创建一个新的对象返回给调用者
def __sub__(self, rhs):
v = self.data - rhs.data
return Mynumber(v)
n1 = Mynumber(100)
n2 = Mynumber(200)
n3 = n1.__add__(n2)
# n3 = n1 + n2 # 可以调用# 等同于 n3 = n1.__add__(n2)
# 自定义的类不能直接用运算符,需要运算符重载
print(n3)
n4 = n3 - n2 # 等同于 n4 = n3.__sub__(n2)
print('n4=', n4)
说明:
运算符重载的方法的参数已经有固定的含义,不建议改变原有的运算符的含义及参数的意义
二元运算符的重载方法格式:
def __xxx__(self, other):
语句块
练习一:
实现两个自定义列表的相加
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
.....
# 实现两个自定义列表的相加
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __add__(self, rhs):
L = self.data + rhs.data
return MyList(L)
def __mul__(self, rhs):
if type(rhs) is int:
L = self.data * rhs
return MyList(L)
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L3 = L1 + L2
print(L3)
L4 = L2 + L1
print(L4)
#试想能否实现一下操作?
L5 = L1 * 3
print(L5)
反向算术运算符的重载
当运算符左侧为内建类型,右侧为自定义类型进行算术运算符运算时会出现
TypeError错误,因无法修改内建类型的代码运算符重载,此时需要使用
反向算术运算符重载
反向r算术运算符的重载:
方法名 运算符表达式 说明
__radd__(self,lhs) lhs + self 加法
__rsub__(self,lhs) lhs - self 减法
__rmul__(self,lhs) lhs * self 乘法
__rtruediv__(self,lhs) lhs / self 除法
__rfloordiv__(self,lhs) lhs // self 地板除
__rmod__(self,lhs) lhs % self 取模(求余)
__rpow__(self,lhs) lhs ** self 幂运算
lhs为左手边
示例:
mylist1.py
#此示例示意反向运算符的重载
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __add__(self, rhs):
L = self.data + rhs.data
return MyList(L)
def __mul__(self, rhs):
print("mul被调用")
L = self.data * rhs
return MyList(L)
def __rmul__(self, lhs):
print("rmul被调用")
return MyList(self.data * lhs)
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
# L3 = L1 + L2
# print(L3)
# L4 = L2 + L1
# print(L4)
# #试想能否实现一下操作?
# L5 = L1 * 3
# print(L5)
# L6 = 3 * L1
# print(L6)
L1 += L2
L2 *= 3
print(L1)
print(L2)
复合赋值算术运算符的重载
以复合赋值算术运算符 x += y 为例,此运算符会优先调用x.__iadd__(y)
方法,如果没有__iadd__方法时会将复合赋值运算符拆解为:x = x + y
然后调用x = x.__add__(y)方法,如果再不存在__add__方法则会触发
TypeError类型的错误异常
复合赋值算术运算符的重载:
方法名 运算符表达式 说明
__iadd__(self,rhs) self += rhs 加法
__isub__(self,rhs) self -= rhs 减法
__imul__(self,rhs) self *= rhs 乘法
__itruediv__(self,rhs) self /= rhs 除法
__ifloordiv__(self,rhs) self //= rhs 地板除
__imod__(self,rhs) self %= rhs 取模(求余)
__ipow__(self,rhs) self **= rhs 幂运算
示例见
mylist2.py
#此示例示意重载运算符的重载
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __add__(self, rhs):
L = self.data + rhs.data
return MyList(L)
def __mul__(self, rhs):
print("mul被调用")
L = self.data * rhs
return MyList(L)
def __rmul__(self, lhs):
print("rmul被调用")
return MyList(self.data * lhs)
def __iadd__(self, rhs):
print("__iadd__方法被调用")
self.data += rhs.data
return self
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
print(id(L1))
L1 += L2 # L1 = L1 + L2 #L1.__iadd__(L2)
L2 *= 3
print(L1)
print(id(L1)) # id 没有变化,因为未创建新的对象,改变的列表自己
print(L2)
比较算术运算符的重载
方法名 运算符表达式 说明
__lt__(self,rhs) self < rhs 小于
__lt__(self,rhs) self <= rhs 小于等于
__gt__(self,rhs) self > rhs 大于
__ge__(self,rhs) self <= rhs 大于等于
__eq__(self,rhs) self == rhs 等于
__ne__(self,rhs) self != rhs 不等于
注:比较运算符通常返回布尔值True或False
位相关运算符重载
方法名 运算符表达式 说明
__and__(self,rhs) self & rhs 位与
__or__(self,rhs) self | rhs 位或
__xor__(self,rhs) self ^ rhs 位异或
__lshift__(self,rhs) self << rhs 左移
__rshift__(self,rhs) self >> rhs 右移
反向位运算符重载
方法名 运算符表达式 说明
__rand__(self,lhs) lhs & self 位与
__ror__(self,lhs) lhs | self 位或
__rxor__(self,lhs) lhs ^ self 位异或
__rlshift__(self,lhs) lhs << self 左移
__rrshift__(self,lhs) lhs >> self 右移
复合赋值位算术运算符的重载:
方法名 运算符表达式 说明
__iand__(self,rhs) self &= rhs 位与
__ior__(self,rhs) self |= rhs 位或
__ixor__(self,rhs) self ^= rhs 位异或
__ilshift__(self,rhs) self <<= rhs 左移
__irshift__(self,rhs) self >>= rhs 右移
一元运算符的重载
方法名 运算符表达式 说明
__neg__(self) - self 负号
__pos__(self) + self 正号
__invert__(self) ~ self 取反
语法:
class 类名:
def __xxx__(self):
....
示例见:
mylist3.py
#此示例示意一元运算符的重载
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __neg__(self):
L = [-x for x in self.data]
return MyList(L)
L1 = MyList([1, -2, 3, -4, 5])
L2 = -L1
print(L2)
in / not in 运算符重载
格式:
def __contains__(self, e):
语句
注: in / not in 返回布尔值 True/False
当重载了__contains__后,in 和 not in 运算符都可用
not in 运算符的返回值与in 相反
示例见:
mylist4.py
#此示例示意in/not in运算符的重载
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __contains__(self, e):
return e in self.data
#等同于 return True if e in self.data else False
L1 = MyList([1, -2, 3, -4, 5])
if 2 in L1: #等同于 if L1.__contains__(2)
print("2在L1内")
else:
print('2不在L1内')
if 4 not in L1: # 等同于if not L1.__contains__(4)
print('4不在L1内')
else:
print("4在L1内")
索引和切片运算符的重载方法:
方法名 运算符表达式 说明
__getitem__(self,i) x = self[i] 索引/切片取值
__setitem__(self,i,v) self[i] = v 索引/切片取值
__delitem__(self,i) del self[i] del语句删除索引/切片
作用:
让自定义类型的对象能够支持索引切片操作
示例见:
mylist5.py
#此示例示意索引和切片运算符的重载方法
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __getitem__(self,i):
'索引取值,i绑定[]内的元素'
return self.data[i] # 返回data绑定列表中的第i个元素
def __setitem__(self,i,v):
'''此方法可以让自定义的列表支持索引赋值操作'''
print('__setitem__被调用,i=', i, 'v=', v)
self.data[i] = v
def __delitem__(self,i):
print("__delitem__被调用")
del self.data[i] # self.data.pop[i]
L1 = MyList([1, -2, 3, -4, 5])
x = L1[3]
print(x)
L1[3] = 400
print(L1)
del L1[3]
print(L1)
print(L1[::2]) # 切片取值
mylist6.py
#此示例示意slice构造函数
class MyList:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'MyList={}'.format(self.data)
def __getitem__(self,i):
'索引取值,i绑定[]内的元素'
if type(i) is int:
print("用户正在用索引取值")
elif type(i) is slice:
print("用户正在用切片取值")
print("切片的起点是:",i.start)
print("切片的终点是:",i.stop)
print("切片的步长是:",i.step)
elif type(i) is str:
print('用户正在用字符串进行索引取值')
return self.data[i] # 返回data绑定列表中的第i个元素
L1 = MyList([1, -2, 3, -4, 5])
print(L1[::2]) # 切片取值
slice构造函数
作用:
用于创建一个slice对象,此对象用于切片操作的传值
格式:
slice(start=None,stop=None,step=None)
slice对象的实例属性:
start 切片的起始值 默认为None
stop 切片的终止值 默认为None
step 切片的步长 默认为None
特性属性 @property(了解)
实现其他语言拥有的getter(获取者) 和setter(设置者)功能
作用:
用来模拟一个属性
通过@property装饰器,可以对模拟属性的赋值和取值加以控制
示例见:
property.py
class Student:
def __init__(self, s):
self.__score = s
def setscore(self,s):
'''此方法用于设置值加以限制以保证数据的准确性,setter用来设置数据'''
if 0 <= s <= 100:
self.__score = s
def getscore(self, s):
'''getter只用来获取数据'''
return self.__score
s = Student(50)
s.setscore(100)
property2.py
class Student:
def __init__(self, s):
self.__score = s
@property
def score(self, s):
'''此方法用于设置值加以限制以保证数据的准确性,setter用来设置数据'''
print("setter被调用")
if 0 <= s <= 100:
self.__score = s
@score.setter
def score(self, s):
'''getter只用来获取数据'''
print('getter被调用')
return self.__score
s = Student(50)
s.setscore(100)
score = s.score # 访问特性属性score,实质调用原来的s.score()
print('成绩是:',score)
实现有序集合类OrderSet,能实现两个集合的交集 &, 并集|,
补集 - ,对称补集^, == ,!=, in/not in 等操作
要求:集合内部用list存储数据
class OrderSet:
def __init__(self, it = None):
if it is None:
self.data = []
elif it:
self.data = [x for x in it]
def __repr__(self):
return 'OrderSet={}'.format(self.data)
def __and__(self, rhs):
return OrderSet(x for x in self.data if x in rhs.data )
def __sub__(self, rhs):
return OrderSet(x for x in self.data if x not in rhs.data)
def __or__(self, rhs):
return OrderSet(self.data + [x for x in rhs.data if x not in self.data ])
def __xor__(self, rhs):
return (self - rhs) | (rhs - self)
def __ne__(self, rhs):
return self.data != rhs.data
def __eq__(self, rhs):
return self.data == rhs.data
def __contains__(self, rhs):
return rhs in self.data
s1 = OrderSet([1,2,3,4])
s2 = OrderSet([3,4,5])
print(s1 & s2) # OrderSet([3,4])
print(s1 | s2) # OrderSet([1,2,3,4,5])
print(s1 - s2) # OrderSet([1,2])
print(s1 ^ s2) # OrderSet([1,2,5])
if OrderSet([1,2,3]) != OrderSet([1,2,3,4]):
print("不相等")
else:
print("相等")
if s1 == OrderSet([3,4,5]):
print('s1 == OrderSet([3,4,5])')
if 2 in s1:
print('2 in s1 返回真')
else:
print("返回假")