day20笔记
函数
说明
getattr(obj, name[, default])
从一个对象得到对象的属性;getattr(x, 'y') 等同于x.y; 当属性不存在时,如果给
出default参数,则返回default,如果没有给出default 则产生一个AttributeError错误
hasattr(obj, name)
用给定的name返回对象obj是否有此属性,此种做法可以避免在getattr(obj, name)时引发错误
setattr(obj, name, value)
给对象obj的名为name的属性设置相应的值value, set(x, 'y', v) 等同于 x.y = v
delattr(obj, name)
删除对象obj中的name属性, delattr(x, 'y') 等同于 del x.y
对象属性管理函数:
异常(高级)
异常相关的语句:
try-except
try-finally
raise 触发异常,发生错误通知
assert 根据条件触发AssertionError类型的错误通知
with 语句
with 语句
语法:
with 表达式1 [as 变量1],表达式2 [as 变量2], ...:
语句块
作用:
使用于对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的'清理'操作,并释放资源
如: 文件使用后自动关闭,线程中锁的自动获取和释放等
说明:
执行表达式 用as 子句中的变量绑定生成的对象
with 语句并不必变异常的状态
示例见:
with.py
# 此示例示意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, '失败')
环境管理器(也有叫上下文管理器)
1. 类内有__enter__方法 和 __exit__ 实例方法的类被称为环境管理器
2. 能够用with语句进行管理的对象必须是环境管理器
3. __enter__将在进入with语句时被调用,并返回由 as 变量绑定的对象
4. __exit__ 将在离开with语句时被调用, 且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理
示例见:
with4.py
# 此示例示意环境管理器类的定义的使用
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) 右手边
示例见:
mynumber.py
# 此示例示意自定义的类通过运算符重载实现运算符操作
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):
运算规则的语句...
练习:
修改昨天的课后练习 MyList 实现两个自定义的列表相加
class MyList:
.....
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L3 = L1 + L2
print(L3) # MyList([1, 2, 3, 4, 5, 6])
L4 = L2 + L1
print(L4) # MyList([4, 5, 6, 1, 2, 3])
思考,能否实现MyList类型的对象与整数相乘?
L5 = L1 * 2
print(L5) # ???
反向算术运算符的重载
当运算符的左侧为内建类型时,右侧为自定义类型进行算术运算时,会出现TypeError错误,因无法修改内建类型的代码来实现运算符重载,此时需要使用反向算术运算符重载来完成重载
反向算术运算重载
方法名 运算符和表达式 说明
__radd__(self, rhs) lhs + self 加法
__rsub__(self, rhs) lhs - self 减法
__rmul__(self, rhs) lhs * self 乘法
__rtruediv__(self, rhs) lhs / self 除法
__rfloordiv__(self, rhs) lhs // self 地板法
__rmod__(self, rhs) lhs % self 求余(取模)
__rpow__(self, rhs) lhs ** self 冪运算
复合赋值算术运算符重载
以复合赋值算术运算符 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 冪运算
比较运算符的重载
方法名 运算符和表达式 说明
__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, 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):
...
示例见:
mylist5.py
# 此示例示意一元运算符的重载
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 成员运算
示例见:
mylist6.py
# 此示例示意一元运算符的重载
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):
return e in self.data
L1 = MyList([1, -2, 3, -4, 5])
if 3 in L1:
print("3 在 L1内")
else:
print("3 不在 L1内")
if 4 not in L1:
print('4 不在L1内')
else:
print('4 在L1内')
索引和切片运算符的重载
[]
重载方法 运算符和表达式 说明
__getitem__(self, i) x = self[i] 索引/切片取值
__setitem__(self,i,val) self.[i]=val 索引/切片赋值
__delitem__(self, i) del self[i] del语句索引/切片
作用:
让自定义的类型的对象能够支持索引和切片操作
示例见:
mylist7.py
# 此示例示意[]运算符的重载
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 要片的步长
示例见:
mylist8.py # 切片取值
# 此示例示意[]运算符的重载
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)
if type(i) is slice:
print("您正在执行切片取值操作")
print("起始值是:", i.start)
print("终止值是:", i.stop)
print("步长是:", i.step)
return self.data[i]
L1 = MyList([1, -2, 3, -4, 5])
x = L1[1:8:2]
print(x) #
特性属性 @property
实现其它语言所拥有的 getter 和 setter功能
作用:
用来模拟一个属性
通过@property装饰器可以对模拟的属性赋值和取值加以控制
示例见:
property.py
# 此示例示意特性属性的用法
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) # ...
property2.py
# 此示例示意特性属性的用法
class Student:
def __init__(self, score):
self.__score = score
@property
def score(self): # score = propery(score)
'''实现getter'''
return self.__score
@score.setter
def score(self, s):
'''实现setter'''
print("正在调用setter")
if 0 <= s <= 100:
self.__score = s
else:
raise ValueError
s = Student(59)
print(s.score) # print(s.get_score())
s.score = 97 # s.set_score(97)
print(s.score) # ...