python day18 异常(高级) 一元运算符重载 、 关系运算符的重载 、

目录:

异常(高级) 一元运算符重载 、 关系运算符的重载 、

with语句

语法:

with 表达式1 [as 变量名1], 表达式2 [as 变量名2], ...

作用:

用于对资源访问的场合,确保使用过程中不管是否发生异常,都会执行必要有”清理”操作,并释放资源.
如:
文件打开后自动关闭,线程中锁的自动获取和释放(线程后面会讲)

说明:

with语句与try-finally相似,并不会必变异常状态
as 子句用于绑定表达式创建的对象

示例见:

 本示例示意with语句的使用方法

# 打开文件读取文件数据(try-finally来实现关闭文件)
# def read_file():
#     try:
#         f = open("abcd.txt")
#         try:
#             while True:
#                 s = f.readline()
#                 if not s:
#                     break  # return
#                 int(input("请输入任意数字打印下一行:"))
#                 print(s)
#         finally:
#             print("文件已经关闭")
#             f.close()
#     except IOError:
#         print("出现异常已经捕获!")
#     except ValueError:
#         print("程序已转为正常状态")


# 打开文件读取文件数据(with来实现关闭文件)
def read_file():
    try:
        # f = open("abcd.txt")
        with open('abcd.txt') as f:
            while True:
                s = f.readline()
                if not s:
                    break  # return
                int(input("请输入任意数字打印下一行:"))
                print(s)
            print("文件已经关闭")

    except IOError:
        print("出现异常已经捕获!")
    except ValueError:
        print("程序已转为正常状态")


read_file()
print("程序结束")

环境管理器:

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

示例:

# 本程序示意自定义的类作为环境管理器使用
class FileWriter:
    def __init__(self, filename):
        self.filename = filename  # 此属性用于记住文件名

    def writeline(self, s):
        '''此方法用于向文件内写入字符串,同时自动添加换行'''
        self.file.write(s)
        self.file.write('\n')

    def __enter__(self):
        '''此方法用于实现环境管理器'''
        self.file = open(self.filename, 'w')
        print("已进入__enter__方法,文件打开成功")
        return self  # 返回值向用于 with中的as 绑定

    def __exit__(self, exec_type, exec_value, exec_tb):
        '''
        exec_type  为异常类异,没有异常发生时为None
        exec_value 为错误的对象,没有异常时为None
        exec_tb    为错误的traceback对象
        '''
        self.file.close()
        print("文件", self.filename, "已经关闭")
        if exec_type is None:
            print("退出with时没有发生异常")
        else:
            print("退出with时,有异常,类型是", exec_type,
                  "错误是", exec_value)
        print("__exit__法被调用,已离开with语句")


try:
    with FileWriter('log.txt') as fw:
        while True:
            s = input("请输入一行: ")
            if s == 'exit':
                break
            if s == 'error':
                raise ValueError("故意制造的值错误")
            fw.writeline(s)
except:
    print("有错误发生,已转为正常")

print("这是with语句之外,也是程序的最后一条语句")

练习:

实现文件的复制(建议使用二进制方式进行操作)
$ python3 mycp.py
请输入源文件: /etc/passwd
请输入目标文件: ./mypass.txt
提示: ‘文件复制成功’ 或 ‘文件复制失败’
(建议使用with语句打开文件)

运算符重载:
什么是运算符重载
让自定义的类生成的对象(实例)能够使用运算符进行操作
作用:
让实例象数学表达式一样进行运算操作
让程序简洁易读
说明:
运算符重载方法的参数已经有固定的含义,不建议改变原有的含义

各种运算重载

算术运算符:

方法名 运算符
add 加法 +
sub 减法 -
mul 乘法 *
truediv 除法 /
floordiv 地板除 //
mod 取模(求余) %
pow 幂 **

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

def __xxx__(self, other):
....

示例:


# 此程序示意运算符重载
class MyNumber:
    def __init__(self, v):
        self.data = v

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

    def __add__(self, other):
        print("__add__方法被调用")
        obj = MyNumber(self.data + other.data)
        return obj

    def __sub__(self, other):
        return MyNumber(self.data - other.data)


n1 = MyNumber(100)
n2 = MyNumber(200)
# n3 = n1.__add__(n2)
n3 = n1 + n2  # 等同于 n1.__add__(n2)
print(n3)
n4 = n2 - n1
print('n4 =', n4)  # MyNumber(100)

练习:

实现两个自定义表的相加

class MyList:
      def __init__(self, iterable):
          self.data = [x for x in iterable]
      ...  # 类内以下的部分自己实现

  L1 = MyList([1,2,3])
  L2 = MyList(range(4, 7))
  L3 = L1 + L2
  print("L3 =", L3)  # MyList([1,2,3,4,5,6])
  L4 = L1 * 2  # 实现乘法运算
  print('L4 =', L4)  # MyList([1,2,3,1,2,3])

反向算术运算符:

方法名 运算符
radd 加法 +
rsub 减法 -
rmul 乘法 *
rtruediv 除法 /
rfloordiv 地板除 //
rmod 取模(求余) %
rpow 幂 **

示例见:

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

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

    # def __add__(self, rhs):
    #     return MyList(self.data + rhs.data)

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

    def __rmul__(self, lhs):
        print("__rmul__被调用, lhs=", lhs)
        return MyList(self.data * lhs)  # lhs (left hand side)


L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
L4 = L1 * 2  # 实现乘法运算
print('L4 =', L4)  # MyList([1,2,3,1,2,3])
L5 = 2 * L1  # 可以吗?
print(L5)

复合赋值运算符重载:

方法名 运算符
iadd 加法 +=
isub 减法 -=
imul 乘法 *=
itruediv 除法 /=
ifloordiv 地板除 //=
imod 取模(求余) %=
ipow 幂 **=

示例见:

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

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

    def __add__(self, rhs):
        print("__add__方法被调用")
        return MyList(self.data + rhs.data)

    def __iadd__(self, rhs):
        print("__iadd__方法被调用")
        self.data.extend(rhs.data)
        return self

L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
print("id(L1) =", id(L1))
L1 += L2  # 相当于 L1 = L1 + L2
print('L1 =', L1)
print("id(L1) =", id(L1))

问题:
# 算法1
a = [100]
def test(x):
x = x + x
print(x)
test(a)
print(a)

# 解法2
a = [100]
def test(x):
x += x # 此处与上题不同。结果也会不同
print(x)
test(a)
print(a)

比较的运算符的重载

方法名 运算符
lt < 小于
le <= 小于等于
gt > 大于
ge >= 大于等于
eq == 等于
ne != 不等于

注:
比较运算符通常返回True或False

位运算符重载

方法名 运算符
inert ~ 取反(一元运算符)
and & 位与(交集)
or | 位或(并集)
xor ^ 位异或(对称补集)
lshift << 左移
rshift >> 右移

反向位运算符重载:

方法名 运算符
rand & 位与(交集)
ror | 位或(并集)
rxor ^ 位异或(对称补集)
rlshift << 左移
rrshift >> 右移

复合赋值运算符重载:

方法名 运算符
iand &= 位与(交集)
ior |= 位或(并集)
ixor ^= 位异或(对称补集)
ilshift <<= 左移
irshift `>>= 右移

一元运算符的重载:

方法名 运算符
neg
    负号
pos
    正号
invert ~ 按位取反

格式:

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):
        print("__neg__方法被调用!")
        L = (-x for x in self.data)
        return MyList(L)


L1 = MyList([1, -2, 3, -4, 5])
print("L1 =", L1)
L2 = -L1
print("L2 =", L2)

in / not in运算符的重载

格式:

def __contains__(self, e): # e代表元素
...

说明:

not in 相当于 in取反,所有只需要重载in 即可

示例见:

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

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

    def __contains__(self, e):  # e 代表测试元素
        print("__contains__被调用")
        for x in self.data:
            if e == x:  # 如果相同,则说明e在列表中
                return True
        return False


L1 = MyList([1, -2, 3, -4, 5])
if 2 in L1:  # 需要重载 __contains__方法
    print("2在L1中")
else:
    print("2 不在L1中")

索引和切片运算符的重载:

重载方法:

  1. 方法

    方法名 作用
    getitem(self, i) 用于索引/切片取值
    setitem(self, i) 用于索引/切片赋值
    delitem(self, i) 用于del语句删除索引操作
  2. 作用:
    让自定义的类型的对象能够支持索引和切片操作
  3. 示例见:

    
    
    # 此示例示意索引 index 和切片 slice 运算符的重载
    
    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("__getitem__被调用", i)
            return self.data[i]
    
        def __setitem__(self, i, v):
            self.data[i] = v
    
    L1 = MyList([1, -2, 3, -4, 5])
    print(L1[2])  # 3?
    L1[1] = 2
    print(L1)
  4. 练习:
    实现有序集合类 OrderSet(), 能实现两个集合的交集 &, 并集 |
    补集 -, 对称补集 ^, ==, != 等操作(写集合相同)
    要求:
    集合内部用list存储
    class OrderSet:
    def init(self, iterable):
    self.data = [x for x in iterable]

    测试用例:
    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(“不相同”)
    其它自己测试….

猜你喜欢

转载自blog.csdn.net/luohongtucsdn/article/details/80704803