高级异常、运算符重载

高级异常

回顾异常相关的语句:

  try-except  用来捕获异常的通知

  try-finally  用来做一定要做的事

  reise    用来发生异常通知

  assert    用来根据条件来发出AssertionError类型的异常通知

with语句

  语句: with 表达式1 [as 变量1],表达式2 [as 变量2]:

         语句块

  作用:使用于对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的'清理'操作,并释放资源

  如:文件使用后自动关闭;线程中锁定的自动获取和释放等

 1 def read_from_file(filename='info.txt'):
 2     try:
 3         with open(filename) as f:
 4             print("正在读取文件")
 5             n = int(f.read())
 6             print('n=', n)
 7             print('文件已经关闭')
 8         # f = open(filename)
 9         # try:
10         #     print("正在读取文件")
11         #     n = int(f.read())
12         #     print("n=", n)
13         # finally:
14         #     f.close()
15         #     print("文件已经关闭")
16     except OSError:
17         print("文件打开失败")
18 
19 
20 read_from_file()
用with语句代替try-finally语句

 

环境管理器

1、类内有__enter____exit__实例方法的类被称为环境管理器

2、能够用with语句管理的对象必须是环境管理器

3、 __enter__方法将在进入with语句时被调用,并返回由as变量管理的对象

4、__exit__将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理

 1 class A:
 2     def __enter__(self):
 3         print("已进入with语句")
 4         return self  # 返回的对象将由 as绑定
 5 
 6     def __exit__(self, exc_type, exc_val, exc_tb):
 7         print("已离开with语句")
 8 # a = A()
 9 with A() as a:
10     print("这是with语句内的一条语句")
11     int(input("请输入整数: "))
环境管理器
1 已进入with语句
2 这是with语句内的一条语句
3 请输入整数: 2
4 已离开with语句
结果

对象的属性管理函数:

1、getattr(obj, name[, default])从一个对象得到对象的属性;getattr(x, 'y') 等同于x.y;当属性不存在时,如果给出default参数,则返回default,如果没有给出default则产生一个AttributeError错误

2、hasattr(obj, name)用给定的name返回对象obj是否有此属性,此种做法可以避免在getattr(obj, name)时引发错误

3、setattr(obj, name, value)给对象obj的名为name的属性设置相应的值value, set(x,'y', v) 等同于 x.y = v

4、delattr(obj, name)删除对象obj中的name属性,delattr(x, 'y') 等同于 del x.y

 1 class Car:
 2     def __init__(self, c, b):
 3         self.color, self.brand = c, b
 4 
 5     def get_car_attr(self, attr_name):
 6         '''此方法用于获取对象的属性,如果属性名attr_name
 7         在此对象内不存在则返回 None
 8         '''
 9         return getattr(self, attr_name, None)
10 
11 c1 = Car('黑色', 'Benz')
12 v = c1.get_car_attr('color')
13 # try:
14 #     v = c1.__dict__['aaaaa']
15 # except KeyError:
16 #     v = None
17 if v is None:
18     print("没有颜色属性")
19 else:
20     print("颜色是:", v)
getatter(obj,name[,default])

运算符重载

  让自定义的类生成的对象(实例)能够使用运算符进行操作

作用:让自定义的类的实例像内建对象一样能够运行运算符操作,让程序简单易读,对自定义的对象,将运算符赋予新的运算规则

 

算术运算符的重载:

  __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 hands side)  右手边

 1 class MyNumber:
 2     def __init__(self, v):
 3         self.data = v
 4 
 5     def __repr__(self):
 6         return 'MyNumber(%d)' % self.data
 7 
 8     # def myadd(self, other):
 9     #     v = self.data + other.data
10     #     return MyNumber(v)
11 
12     def __add__(self, other):
13         print("__add__被调用")
14         v = self.data + other.data
15         return MyNumber(v)
16 
17     def __sub__(self, rhs):
18         v = self.data - rhs.data
19         return MyNumber(v)
20 
21 n1 = MyNumber(100)
22 n2 = MyNumber(200)
23 # n3 = n1.myadd(n2)
24 # n3 = n1.__add__(n2)
25 n3 = n1 + n2  # __add__被调用
26 print(n3)   # MyNumber(300)
27 n4 = n3 - n2
28 print(n4)   # MyNumber(100)
算术运算符重载
 1 class MyList:
 2     def __init__(self, iterable):
 3         self.data = list(iterable)
 4 
 5     def __add__(self, rhs):
 6         return MyList(self.data + rhs.data)
 7 
 8     def __repr__(self):
 9         return 'MyList(%r)' % self.data
10 
11     def __mul__(self, rhs):  # rhs 绑定整数
12         return MyList(self.data * rhs)
13 
14 L1 = MyList([1, 2, 3])
15 L2 = MyList([4, 5, 6])
16 L3 = L1 + L2  # 等同于L1.__add__(L2)
17 print(L3)  # MyList([1,2,3,4,5,6])
18 L4 = L2 + L1  # 等同于L2.__add__(L1)
19 print(L4)  # MyList([4,5,6,1,2,3])
20 L5 = L1 * 2  # L1.__mul__(2)
21 print(L5)  # MyList([1,2,3,1,2,3])
算术运算符重载

反向算术运算符的重载

  __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   冪

 1 class MyList:
 2     def __init__(self, iterable):
 3         self.data = list(iterable)
 4 
 5     def __add__(self, rhs):
 6         return MyList(self.data + rhs.data)
 7 
 8     def __repr__(self):
 9         return 'MyList(%r)' % self.data
10 
11     def __mul__(self, rhs):  # rhs 绑定整数
12         print('__mul__被调用')
13         return MyList(self.data * rhs)
14     def __rmul__(self, lhs):
15         print('__rmul__被调用')
16         return MyList(self.data * lhs)
17 
18 L1 = MyList([1, 2, 3])
19 L2 = MyList([4, 5, 6])
20 L5 = L1 * 2  # L1.__mul__(2)
21 print(L5)  # MyList([1,2,3,1,2,3])
22 
23 L6 = 2 * L1  # 2.__mul__(L1)
24 print(L6)
反向算术运算符重载

复合赋值算术运算符的重载

  __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    冪

 1 class MyList:
 2     def __init__(self, iterable):
 3         print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
 4         self.data = list(iterable)
 5 
 6     def __add__(self, rhs):
 7         print('__add__被调用')
 8         return MyList(self.data + rhs.data)
 9 
10     def __repr__(self):
11         return 'MyList(%r)' % self.data
12 
13     def __iadd__(self, rhs):
14         print("__iadd__被调用!!!!")
15         self.data.extend(rhs.data)
16         return self
17 
18 L1 = MyList([1, 2, 3])  # aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
19 L2 = MyList([4, 5, 6])  # aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
20 L1 += L2  # 当没有__iadd__方法时,等同于调用L1 = L1 + L2    __iadd__被调用!!!!
21 print(L1)   # MyList([1, 2, 3, 4, 5, 6])
View Code

比较运算符的重载

  __lt__(self, rhs)   self < rhs      小于
  __le__(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

位运算符重载

  __invert__(self)      ~ self       取反(一元运算符)
  __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):

 1 class MyList:
 2     def __init__(self, iterable):
 3         print("__init__被调用")
 4         self.data = list(iterable)
 5 
 6     def __repr__(self):
 7         return 'MyList(%r)' % self.data
 8 
 9     def __neg__(self):
10         '''此方法用来制定 - self 返回的规则'''
11         # L = [-x for x in self.data]
12         L = (-x for x in self.data)
13         return MyList(L)
14 
15 L1 = MyList([1, -2, 3, -4])
16 L2 = -L1
17 print(L2)
View Code

运算符重载说明:
  运算符重载不能改变运算符的优先级

Python类名最好用驼峰命名法:
MyList MyRange 大驼峰(所有单词首字母大写,其余小写)
getStudentAge 小驼峰(第一个单词首字母小写,其它首字母大写)

in / not in 运算符的重载

重载方法:
  __contains__(self, e)   e in self  成员运算

 1 class MyList:
 2     def __init__(self, iterable):
 3         print("__init__被调用")
 4         self.data = list(iterable)
 5 
 6     def __repr__(self):
 7         return 'MyList(%r)' % self.data
 8 
 9     def __contains__(self, e):
10         '''此方法用来实现 in / not in 运算符的重载'''
11         print("__contains__被调用")
12         for x in self.data:
13             if x == e:
14                 return True
15         return False
16 
17 
18 L1 = MyList([1, -2, 3, -4])
19 if -2 in L1:
20     print('-2 在 L1 中')
21 else:
22     print('-2 不在 L1中')
23 
24 
25 # 当MyList的类内重载了__contains__方法,则not in也同时可用
26 if -3 not in L1:
27     print("-3 不在 L1中")
28 else:
29     print('-3 在 L2中')
View Code

索引和切片运算符的重载

  __getitem__(self, i)     x = self[i] 索引/切片取值
  __setitem__(self, i, v)      self[i] = v 索引/切片赋值
  __delitem__(self, i)        del self[i] del语句删除索引等

  作用:
  让自定义的类型的对象能够支持索引和切片操作

 1 class MyList:
 2     def __init__(self, iterable):
 3         print("__init__被调用")
 4         self.data = list(iterable)
 5 
 6     def __repr__(self):
 7         return 'MyList(%r)' % self.data
 8 
 9     def __getitem__(self, i):
10         print("__getitem__被调用, i=", i)
11         # if type(i) is not int:
12         #     raise TypeError
13         return self.data[i]
14 
15     def __setitem__(self, i, v):
16         print("__setitem__被调用, i=", i, 'v =', v)
17         self.data[i] = v  # 修改data绑定的列表
18 
19 
20 L1 = MyList([1, -2, 3, -4])
21 v = L1[-1]
22 print(v)
23 
24 L1[1] = 2  # 等同于调用 L1.__setitem__(1, 2)
25 print(L1)
26 
27 # 以下操作会出错
28 # print(L1[100000000000])
29 # print(L1['hello'])
View Code

slice 构造函数

作用: 用于创建一个Slice切片对象, 此对象存储一个切片的起始值,终止值和步长信息
  slice(start, stop=None, step=None) 创建一个切片对象
slice的对象的属性:
  s.start 切片起始值,默认为None
  s.stop 切片终止值,默认为None
  s.step 切片步长 ,默认为None

 1 class MyList:
 2     def __init__(self, iterable):
 3         print("__init__被调用")
 4         self.data = list(iterable)
 5 
 6     def __repr__(self):
 7         return 'MyList(%r)' % self.data
 8 
 9     def __getitem__(self, i):
10         print("__getitem__被调用, i=", i)
11         if type(i) is int:
12             print("正在做索引操作")
13         elif type(i) is slice:
14             print("正在做切片操作")
15             print("切片的起始值:", i.start)
16             print("切片的终止值:", i.stop)
17             print("切片的步长:", i.step)
18         else:
19             raise KeyError
20         return self.data[i]
21 
22 
23 L1 = MyList([1, -2, 3, -4, 5, -6])
24 
25 print(L1[::2])  # 等同于调用L1[slice(None, None, 2)]
View Code

 

posted @ 2018-07-29 14:13  凌逆战  阅读(404)  评论(0编辑  收藏  举报