属性管理函数
函数 | 说明 |
---|---|
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 |
异常(高级)
with 语句
语法:with 表达式1 [as 变量名1], 表达式2 [as 变量名2], ...
作用:
用于对资源访问的场合,确保使用过程中不管是否发生异常,都会执行必要有'清理'操作,并释放资源
如:
文件打开后自动关闭,线程中锁的自动获取和释放(线程后面会讲)
说明:
with 语句与 try-finally相似,并不会改变异常状态
as 子句用于绑定表达式创建的对象
示例:
# 此示例示意with语句的使用方法
# 打开文件读取文件数据
def read_file():
try:
f = open('a.txt')
try:
while True:
s = f.readline()
if not s:
return
int(input('请输入任意数字打印下一行:'))
print(s.rstrip())
finally:
f.close()
print('文件关闭')
except IOError:
print('已转正常')
except ValueError:
print('已转正常')
def read_file_with():
try:
with open('a.txt') as f:
while True:
s = f.readline()
if not s:
break
int(input('请输入任意数字打印下一行:'))
print(s.rstrip())
except IOError:
print('已转正常')
except ValueError:
print('已转正常')
if __name__ == '__main__':
read_file()
# 下为with 语句
read_file_with()
环境管理器:
1、类内有__enter__和__exit__方法的类被称为环境管理器2、能够用with进行管理的对象必须是环境管理器
3、__enter__ 将在进入with语句时被调用,并返回有as变量管理的对象
4、__exit__将在离开with语句是被调用,且可以用参数来判断离开with语句时是否出现异常并做出相应的处理
示例:
# 本程序示意自定义的类作为资源管理器使用
class FileWrite:
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, exc_type, exc_val, exc_tb):
'''
:param exc_type: 为异常类型,没有异常发生时为None
:param exc_val:为错误的对象,没有异常时为None
:param exc_tb: 为错误的traceback对象
:return:
'''
self.file.close()
print('文件', self.filename, '已经关闭')
if exc_type is None:
print('退出with语句时没有异常')
else:
print('退出with语句时有异常,类型是', exc_type, '错误是', exc_val)
print('__exit__方法被调用,已离开with语句')
if __name__ == '__main__':
try:
with FileWrite('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语句打开文件
'''
def cp(src_file, dst_file):
'''
:param sou_file: 源文件路径
:param obj_file: 目标文件路径
:return: 结果提示
'''
try:
with open(src_file, 'rb') as f_s, open(dst_file, 'wb') as f_d:
# 如果此文件过大则分次进行搬移
while True:
b = f_s.read(4096)
if not b: # 如果字节为空停止复制
break
f_d.write(b)
return '文件复制成功'
except:
return '文件复制失败'
def main():
src = input('请输入源文件:')
dst = input('请输入目标文件:')
r = cp(src, dst)
print(r)
if __name__ == '__main__':
main()
运算符重载:
什么是运算符重载:
让自定义的类生成的对象(实例)能够使用运算符进行操作作用:
让实例象数学表达式一样进行运算操作
让程序简洁易读
说明:
运算符重载方法的参数已经有固定的含义,不建议改变与哪有的含义
算数运算符:
方法名 运算符__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):
obj = MyNumber(self.data - other.data)
return obj
n1 = MyNumber(100)
n2 = MyNumber(200)
# n3 = n1.__add__(n2)
n3 = n1 + n2 # 等同于n3 = n1.__add__(n2)o
print('n3 =',n3)
n4 = n2 - n1
print('n4 =',n4)
练习:
实现两个自定义表的相加
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])
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __add__(self, other):
return MyList(self.data + other.data)
def __mul__(self, other):
return MyList(self.data * other)
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(%s)' % self.data
def __mul__(self, rhs):
return MyList(self.data * rhs)
def __rmul__(self, lhs):
print('__rmul__被调用,lhs =', lhs)
return MyList(self.data * lhs)
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('L4 =', L5) # MyList([1, 2, 3, 1, 2, 3])
复合赋值运算符重载
方法名 运算符__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(%s)' % self.data
def __add__(self, other):
print('__add__被调用')
return MyList(self.data + other.data)
def __iadd__(self, other): # 在+=中优先调用此方法,没有则调用__add__方法
print('__iadd__方法被调用')
self.data.extend(other.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))
问题:
# 算法一
a=[100]
def test(x):
x=x+x
print(x)
test(a)
print(a)
# 算法二
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__ >>右移
反向位运算符重载
__rinert__ ~取反(一元运算符)
__rand__ &位与(交集)
__ror__ |位与(并集)
__rxor__ ^位与(差集)
__rlshift__ <<左移
__rrshift__ >>右移
复合赋值运算符重载
__iinert__ ~取反(一元运算符)__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(%s)' % self.data
def __neg__(self):
print('__neg__方法被调用')
return MyList(-x for x in self.data) # 生成器表达式
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(%s)' % self.data
def __contains__(self, e): # e 代表元素
print('__contains__被调用')
for x in self.data:
if 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中')
索引和切片运算符的重载:
重载方法__getitem__(self, item) 用于索引/切片取值
__setitem__(self, key, value) 用于索引/切片赋值
__delitem__(self, key) 用于del语句删除索引操作
作用:
让自定义的类型的对象能够支持索引和切片操作
示例:
# 此示例示意索引 index 运算符重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __getitem__(self, item):
print('__getitem__被调用', item)
return self.data[item]
def __setitem__(self, key, value):
self.data[key] = value
def __delitem__(self, key):
del self.data[key]
L1 = MyList([1, -2, 3, -4, 5])
print(L1[2])
L1 = MyList([1, -2, 3, -4, 5])
L1[1] = 2
print(L1)
# 此示例示意切片 slice 运算符重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __getitem__(self, item):
print('__getitem__被调用', item)
if type(item) is slice:
print('正在进行切片操作')
elif type(item) is int:
print('正在进行索引操作')
return self.data[item]
def __setitem__(self, key, value):
self.data[key] = value
def __delitem__(self, key):
del self.data[key]
L1 = MyList([1, -2, 3, -4, 5])
print(L1[::2]) # ::2等同于slice(None, None, 2)
L1 = MyList([1, -2, 3, -4, 5])
L1[::2] = (2, 4, 6)
print(L1)