python3基础20

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("返回假")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值