(二十)python 异常,运算符重载

目录

异常(高级)

    异常相关的语句:

    with语句

环境管理器(也有叫上下文管理器)

运算符重载

    算术运算重载

    反向算术运算符的重载

    复合赋值算术运算符重载

    比较运算符的重载

    位运算符的重载

    反向位运算符的重载

    复合赋值位运算符的重载

    一元运算符的重载

    索引和切片运算符的重载

      slice 构造函数


对象属性管理函数:
  详见:内建函数.html

getattr(dog1,'color',没有此属性)
hasattr(dog1,'kinds')
delatter = del


异常(高级)

    异常相关的语句:

        try-except
        try-finally
        raise 触发异常,发生错误通知
        assert 根据条件触发AssertionError类型的错误通知
        with 语句

    with语句

        语法:
            with 表达式1[as 变量1], 表达式2 [as 变量2], ...:
                语句块
        作用:
            使用于对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的'清理'操作,并释放资源
            如: 文件使用后自动关闭,线程中锁的自动获取和释放等
        说明:
            执行表达式用as子句中的变量绑定生成的对象
            with 语句并不改变异常的的状态
 

# 此示例示意with语句的用法
src_file = input("请输入源文件: ")

try:
    src = open(src_file, 'rb')
    try:
        try:
            # 准备打开别一个文件
            dst_file = input("请输入目标文件: ")
            dst = open(dst_file, 'wb')
            try:
                # 开始读写文件
                b = src.read()
                dst.write(b)
            finally:
                # 关闭文件
                dst.close()
        except OSError:
            print('打开写文件失败')
    finally:
        src.close()
except OSError:
    print("打开文件", src_file, '失败')
# 此示例示意with语句的用法
src_file = input("请输入源文件: ")
dst_file = input("请输入目标文件: ")

try:
    with open(src_file, 'rb') as src:
        # 准备打开别一个文件
        with open(dst_file, 'wb') as dst:
            # 开始读写文件
            b = src.read()
            dst.write(b)
except OSError:
    print("复制失败")

src_file = input("请输入源文件: ")
dst_file = input("请输入目标文件: ")

try:
    with open(src_file, 'rb') as src, \
         open(dst_file, 'wb') as dst:
        b = src.read()
        dst.write(b)
except OSError:
    print("复制失败")


环境管理器(也有叫上下文管理器)

    1.类内有__enter__方法和__exit__实例方法的类被称为环境管理器
    2.能够用with语句进行管理的对象必须是环境管理器
    3.__enter__将在进入with语句时被调用,并返回由 as 变量绑定的对象
    4.__exit__将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理

# 此示例示意环境管理器类的定义的使用
class A:
    '''此类的对象可以用于with语句进行管理'''
    def __enter__(self):
        print("已经进入with语句")
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        print("已经离开了with语句")
        if exc_type is None:
            print("在with语句内部没有发生异常,正常离开with")
        else:
            print("离开with语句时出现异常")
            print("异常类型是:", exc_type)
            print("错误的值是:", exc_value)

try:
    with A() as a:
        print("这是with语句里打印的")
        3 / 0  # 触发异常
except:
    print("有异常发生,程序已转为正常!")

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 hands side)

# 此示例示意自定义的类通过运算符重载实现运算符操作
class MyNumber:
    def __init__(self, v):
        self.data = v

    def __repr__(self):
        return "MyNumber(%d)" % self.data

    def __add__(self, other):
        '''实现加法操作,生成一个新的对象并返回给调用者'''
        print("__add__方法被调用")
        return MyNumber(self.data + other.data)
    def __sub__(self, rhs):
        return MyNumber(self.data - rhs.data)

n1 = MyNumber(100)
n2 = MyNumber(200)
n3 = n1 + n2  #  等同于n1.__add__(n2)
# n3 = n1.__add__(n2)

print(n1, "+", n2, '=', n3)  # MyNumber(300)    ???
n4 = n1 - n2
print('n4 =', n4)

    二元运算符的重载方法格式:

        def __xxx__(self,other):
            运算规则的语句...


    反向算术运算符的重载

        当运算符的左侧为内建类型时,右侧为自定义类型进行算术运算时,会出现TypeError错误,
        因无法修改内建类型的代码来实现运算符重载,此时需要使用反向运算符重载来完成重载

    反向算术运算重载
    方法名                     运算符和表达式    说明
    __radd__(self,rhs)        rhs  +    self 加法
    __rsub__(self,rhs)        rhs  -    self 减法
    __rmul__(self,rhs)        rhs  *    self 乘法
    __rtruediv__(self,rhs)    rhs  /    self 除法
    __rfloordiv__(self,rhs)   rhs  //   self 地板法
    __rmod__(self,rhs)        rhs  %    self 求余(取模)
    __rpow__(self,rhs)        rhs  **   self 幂运算

# 此示例示意反向算术运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __mul__(self, rhs):
        print("__mul__")
        return MyList(self.data * rhs)

    def __rmul__(self, lhs):
        print("__rmul__被调用")
        return MyList(self.data * lhs)

L1 = MyList([1, 2, 3])
L6 = 2 * L1  # 等同于2.__add__(L1) 或 L1.__rmul__(2)
print(L6)

    复合赋值算术运算符重载

        以复合赋值算术运算符为例x += y 为例,此运算符会优先调用x.__iadd__(y) 方法,
        如果没有__iadd__方法时会将复合赋值运算符拆为x = x + y,然后调用x = x.__add__(y) 方法        
        其它复合赋值算术运算符也具有相同的规则

        复合算术运算重载
        方法名                     运算符和表达式    说明
        __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     幂运算


    比较运算符的重载

        方法名                运算符和表达式      说明
    __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

# 此示例示意比较运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __gt__(self,rhs):
        '''只比较第一个元素'''
        print("__gt__被调用")
        return self.data > rhs.data

    def __eq__(self, rhs):
        print('__eq__被调用')
        return self.data == rhs.data

L1 = MyList([1, 2, 3])
L2 = MyList([1, 2, 3])

print(L1, '>', L2, '=', L1 > L2)
print(L1, '<', L2, '=', L1 < L2)
print(L1, '==', L2, 'is', L1 == L2)
print(L1, '!=', L2, 'is', L1 != L2)


    位运算符的重载

        方法名             运算符和表达式    说明
    __invert__(self,rhs)       ~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, rhs)       lhs &  self     位与
      __ror__(self, rhs)        lhs |  self     位或
      __rxor__(self, rhs)       lhs ^  self     位异或
      __rlshift__(self, rhs)    lhs << self     左移
      __rrshift__(self, rhs)    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       取反

    语法格式:
      def __xxx__(self):
          ...示例:

# 此示例示意一元运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __neg__(self):
        '''规则是正变负,负变正'''
        # L = [-x for x in self.data]
        L = (-x for x in self.data)
        return MyList(L)

L1 = MyList([1, -2, 3, -4, 5])
L2 = -L1  # 等同于L1.__neg__()
print(L2)

    in / not in 运算符

        __contains__(self, e)   e in self   成员运算

    索引和切片运算符的重载

        []
      重载方法               运算符和表达式    说明
    __getitem__(self, i)    x = self[i]  索引/切片取值
    __setitem__(self,i,val) self.[i]=val 索引/切片赋值
    __delitem__(self, i)    del self[i]  del语句索引/切片

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

# 此示例示意[]运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __getitem__(self, i):
        print("i =", i)
        return self.data[i]
    def __setitem__(self, i, val):
        self.data[i] = val

L1 = MyList([1, -2, 3, -4, 5])
x = L1[0]  # L1.__getitem__(0)
print(x)

L1[1] = 2  # L1.__setitem__(1, 2)
print(L1)

      slice 构造函数


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


    特性属性 @property
        实现其它语言所拥有的 getter 和 setter功能

        作用:
            用来模拟一个属性
            通过@property装饰器可以对模拟的属性赋值和取值加以控制

# 此示例示意特性属性的用法
class Student:
    def __init__(self, score):
        self.__score = score

    def get_score(self):
        '''实现getter'''
        return self.__score

    def set_score(self, s):
        '''实现setter'''
        print("正在调用setter")
        if 0 <= s <= 100:
            self.__score = s
        else:
            raise ValueError

    score = property(get_score, set_score)

s = Student(59)
print(s.score)  # print(s.get_score())
s.score = 97  # s.set_score(97)
print(s.score)  # ...


练习:
  实现有序集合类 OrderSet 能实现两个集合的
    交集 &   全集 |  补集 -  对称补集 ^  == / != 
    in / not in 等集合操作
  要求内部用list 存储
  class OrderSet:
      ...

  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, 5])
  if OrderSet([1,2,3]) != OrderSet([1, 2, 3, 4]):
      print("不相等")
  if s2 == OrderSet([3,4,5]):
      print('s2 等于 OrderSet([3,4,5])')
  if 2 in s1:
      print('2 在s1内')

猜你喜欢

转载自blog.csdn.net/zh__quan/article/details/81604268
今日推荐