python基础day20笔记

2018.7.27

day19回顾


  封装
  多态
  继承
多继承
类的__mro__属性 绑定一系列类的元组
 

class A:
    def m():
        pass
class B(A):
    def m():
        pass
class C(B):
    def m():
        pass
c = C()
super(C, c).m()  # 调用B.m()
super(B, c).m()  # 调用A.m() 

函数重写
  repr(x)
  str(x)
  int(x)
  float(x)
  complex(x)
  bool(x)
  abs(x)
  len(x)
  iter(x)
  next(x)

迭代器
  __next__(self)


可迭代对象一定有
  __iter__(self)


生成器函数和生成器表达式


day20笔记


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

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

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

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

示例:
   

class Dog:
    pass
d = Dog()
d.color = '白色'
v = getattr(d, 'color')   # 等同于 v = d.color
v = getattr(d, 'kinds')  # 出错,没有d.kinds属性
v = getattr(d, 'kinds', '没有这个属性')  # v= '没有这个属性'
hasattr(d, 'color')  # True
hasattr(d, 'kinds')  # False
setattr(d, 'kinds', '京巴')  # 等同于d.kinds ='京巴'
hasattr(d, 'kinds')  # True
delattr(d, 'kinds')  # 等同于 del d.kinds
hasattr(d, 'kinds')  # False


异常(高级)
    可以用于异常的语句:
    try-except  # 捕获异常,得到异常通知
    try-finally  # 做任何流程(正常流程/异常流程)都必须要执行的语句
    raise  # 发送异常通知
    assert  # 根据条件发送异常通知

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

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

#  此示例示意用with语句打开文件和自动关闭文件的操作
# try:
#     f = open('a.txt')
#     try:
#         for x in f:
#             print(x)
#             int('abc')  # 出错异常
#     finally:
#         f.close()
# except OSError:
#     print("打开文件失败")
# except ValueError:
#     print('操作文件过程中失败')


try:
    with open('a.txt') as f:
        for x in f:
            print(x)
            int("abc")  # 出现异常
except OSError:
    print("打开文件失败")
except ValueError:
    print('操作文件过程中失败')


  示例2:

# 将之前的练习mycopy复制文件由try-finally 改为
# with语句来实现

src_filename = input("请输入源文件路径名: ")
dst_filename = input('请输入目标文件路径名: ')
try:
    with open(src_filename, 'rb') as src, \
            open(dst_filename, 'wb') as dst:
        while True:
            b = src.read(4096)
            if not b:  # 已经再也读不到数据了
                break
            dst.write(b)
        print("复制成功")
except OSError:
    print("复制失败")

环境管理器
  类内有__enter__ 和 __exit__实例方法的类被称为环境管理器
  能够用with进行管理的对象必须是环境管理器

说明:
    __enter__将在进入with语句时被调用并返回由as变量绑定的对象
    __exit__将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理

示例:

# 此示例示意 让一个自定义的类创建的对象能够使用with语句
class A:
    '''此类的对象可用于with语句进行管'''
    def __enter__(self):
        print("已经进入with语句,资源分配成功!")
        return self  # <<<--此处返回的对象将由 as 变量绑定

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("已经离开with语句,资源释放成功!")
        if exc_type is None:
            print("当离开with语句时没有发生异常")
        else:
            print('有异常发生,异常类型是:', exc_type,
                '异常值是:', exc_val)


with A() as a:
    print("这是with中的语句")
    raise ValueError("故意制造的异常")


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

  作用:
    1. 让自定义的类的实例能够运行运算符操作
    2. 让程序简洁易读
    3. 对自定义对象将运算符赋序新的运算规则
  说明:
    运算符重载方法的参数已经有固定的含义,不建议改变原有的意义

算术运算符重载
       方法名               运算符和表达式   说明
 __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) 右手边

示例:

class MyNumber:
    def __init__(self, val):
        self.data = val

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

    def __add__(self, rhs):
        v = self.data + rhs.data
        return MyNumber(v)  # 创建一个新对象并返回

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

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


练习:
  1. 实现两个自定义的列表相加
  class MyList:
      ....  此处自己实现
  L1 = MyList([1, 2, 3])
  L2 = MyList(range(4, 7))
  L3 = L1 + L2
  print(L3)  # MyList([1, 2, 3, 4, 5, 6])
  L4 = L2 + L1
  print(L4)  # MyList([4, 5, 6, 1, 2, 3])
  L5 = L1 * 2
  print(L5)  # MyList([1, 2, 3, 1, 2, 3])

解析:

class MyList:
    def __init__(self, iterable):
        '''在初始化方法内为每个对象都创建一个data属性
        data 用来绑定每个对象自己的列表'''
        self.data = list(iterable)
        # self.data = [x for x in iterable]  # 等同于上句

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

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

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


L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
L3 = L1 + L2
print(L3)  # MyList([1, 2, 3, 4, 5, 6])
L4 = L2 + L1
print(L4)  # MyList([4, 5, 6, 1, 2, 3])
L5 = L1 * 2
print(L5)  # MyList([1, 2, 3, 1, 2, 3])


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

反向算术运算符重载
       方法名               运算符和表达式   说明
 __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(left hand side) 右手边

示例见:

# 此示例示意返向算述运算符的重载
class MyList:
    def __init__(self, iterable):
        self.data = list(iterable)

    def __repr__(self):
        return 'MyList(%s)' % 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])
L2 = MyList(range(4, 7))
L3 = 2 * L1  # L1.__rmul__(2)
print(L3)

L5 = L1 * 2  # L5 = L1.__mul__(2)
print(L5)  # MyList([1, 2, 3, 1, 2, 3])

复合赋值算术运算符的重载
  以复合赋值算术运算符  x += y 为例,此运算会优先调用x.__iadd__(y) 方法,
  如果没有__iadd__方法时会将复合赋值运算拆解为 x = x + y,然后调用x = x.__add__(y) 方法
  如果再不存在 __add__方法则会触发TypeError异常

  其它复合赋值运算符也具有相同的规则

复合赋值算术运算符重载
       方法名               运算符和表达式   说明
 __iadd__(self, lhs)        lhs +=  self    加法
 __isub__(self, lhs)        lhs -=  self    减法
 __imul__(self, lhs)        lhs *=  self    乘法
 __itruediv__(self, lhs)    lhs /=  self    除法
 __ifloordiv__(self, lhs)   lhs //= self    地板除
 __imod__(self, lhs)        lhs %=  self    取模(求余)
 __ipow__(self, lhs)        lhs **= self    幂


问题:
L = [1, 2, 3]

def f1(lst):
    lst += [4, 5, 6]

f1(L)
print(L)  # [1, 2, 3, 4, 5, 6]  为什么

L = (1, 2, 3)
def f1(lst):
    lst += (4, 5, 6)  # lst = lst + (4, 5, 6)
f1(L)
print(L)  # (1, 2, 3)  为什么

示例1:

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

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

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

    # def __iadd__(self, rhs):
    #     print("__iadd__方法被调用!!!")
    #     self.data += rhs.data  # 把 rhs数据加到现有列表中
    #     return self  # 不创建新对象,把自己返回回去

L = MyList([1, 2, 3])


def f1(lst):
    lst += MyList([4, 5, 6])

f1(L)
print(L)

#__add__方法被调用
#id(r)= 140086953336000
#MyList([1, 2, 3])
##如果是iadd那么优先返回iadd的值,其结果是 #MyList([1, 2, 3, 4, 5, 6])

示例2:

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

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

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

    def __iadd__(self, rhs):
        print("__iadd__方法被调用!!!")
        self.data += rhs.data  # 把 rhs数据加到现有列表中
        return self  # 不创建新对象,把自己返回回去

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


L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
print("L1的ID:", id(L1))
L1 += L2  # 效果等同于 L1 = L1 + L2
print("L1 += L2之后的ID", id(L1))
print(L1)

#L1的ID: 140655827770504
#__iadd__方法被调用!!!
#L1 += L2之后的ID 140655827770504
#MyList([1, 2, 3, 4, 5, 6])

比较运算符的重载

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

示例见:
 

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

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

    def __eq__(self, rhs):
        return self.data == rhs.data

    def __gt__(self, rhs):
        return self.data > rhs.data


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

print(L1 == L2)  # True

print(L1 > L2)  # 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    右移


一元运算符重载
       方法名               运算符和表达式   说明
 __invert__(self)          ~ self      取反(一元运算符)
 __pos__(self)             + self      正号
 __neg__(self)             - self      负号

语法:
   def __xxx__(self):
       ...
示例见:
 

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

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

    def __neg__(self):
        return MyList((-x for x in self.data))

    def __pos__(self):
        return MyList([abs(x) for x in self.data])


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

# 实现用正号运算符返回全部元素为正数的自定义列表
L3 = + L1
print(L3)  # MyList([1, 2, 3, 4, 5])

in / not in 运算符重载
重载方法:
  def __contains__(self, e):
      ....

示例见:

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

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

    def __contains__(self, e):
        return e in self.data

L1 = MyList([1, -2, 3, -4, 5])
print(2 in L1)
print(3 in L1)
print(4 not in L1)
print(5 not in L1)


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

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

示列见:

# 此示例示意 索引/切片 运算符的重载
class MyList:
    def __init__(self, iterable):
        self.data = list(iterable)

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

    def __getitem__(self, i):
        print("索引i的值是:", i)
        return self.data[i]

    def __setitem__(self, i, v):
        print("__setitem__被调用, i=", i, 'v=', v)
        self.data[i] = v

    def __delitem__(self, i):
        del self.data[i]


L1 = MyList([1, -2, 3, -4, 5])
v = L1[2]  # v = 3
print(v)  # 3
L1[1] = 2
print(L1)  # MyList([1, 2, 3, -4, 5])
del L1[3]
print(L1)  # MyList([1, 2, 3, 5])

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

示例:

# 此示例示意 索引/切片 运算符的重载
class MyList:
    def __init__(self, iterable):
        self.data = list(iterable)

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

    def __getitem__(self, i):
        print("索引i的值是:", i)
        if type(i) is int:
            print("正在进行索引操作")
        elif type(i) is slice:
            print("正在进行切片操作")
            print("起始值是:", i.start)
            print("终止值是:", i.stop)
            print("步长值是:", i.step)
        return self.data[i]

    def __setitem__(self, i, v):
        print("__setitem__被调用, i=", i, 'v=', v)
        self.data[i] = v

    def __delitem__(self, i):
        del self.data[i]


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

#索引i的值是: slice(None, None, 2)
#正在进行切片操作
#起始值是: None
#终止值是: None
#步长值是: 2
#[1, 3, 5]

PEP8编码规范文档详见:点击

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

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

class Student:
    def __init__(self, s):
        self.__score = s  # 私有属性,不让其它人任意修改成绩

    @property
    def score(self):
        '''取值实现getter方法'''
        print('正在取值')
        return self.__score

    @score.setter
    def score(self, v):
        '''实现设置者setter,对用户的赋值加以限制'''
        assert 0 <= v <= 100, '成绩不合法'
        self.__score = v


s = Student(59)
print(s.score)  # 希望有一个属能得到成绩
s.score = 80  # 通过s.score 来修改成功
print(s.score)  # 80


练习:
  实现有序集合类 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([3, 4, 5]):
      print("不相等")
  if s2 == OrderSet(3, 4, 5):
     print('s2 == OrderSet(3, 4, 5) is True')
  if 2 in s1:
     print("2在 s1中")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值