函数重载 overwrite
在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)像内建对象一样进行函数操作。
一、对象转字符串函数
repr(x) 返回一个能代表此对象的表达式字符串,通常:eval(repr(obj)) = obj
str(obj) 通过给定对象,返回一个字符串(这个字符串通常是给人阅读的)
换句话说
repr(obj) 返回的字符串是给python用的
str(obj) 返回的字符串是给人看的
repr()和str()的重载方法
repr() 函数的重载方法
def __repr__(self):
...
return 字符串
str() 函数的重载方法
def __str__(self):
...
return 字符串
str(obj) 函数调用方法说明
a、str(obj) 函数先查找obj.__str__() 方法,调用此方法并返回结果
b、如果obj.__str__() 方法不存在,则调用obj.__repr__()方法并返回结果
c、如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示<__main__.MyNumber object at xxx> 格式的字符串
示例
class MyNumber:
def __init__(self, value):
self.data = value
def __str__(self):
# print('正在调用__str__方法,转换为普通字符串')
s = "自定义数据:%d" % self.data
return s
def __repr__(self):
'''此方法供repr(obj)函数调用'''
return 'MyNumber(%d)' % self.data
n1 = MyNumber(100)
print(str(n1)) # 此句等同于print(n1)
print(n1)
print(repr(n1))
二、内建函数重载
__abs__ abs(obj) 函数调用
__len__ len(obj) 函数调用
__reversed__ reversed(obj) 函数调用
__round__ round(obj) 函数调用
示例
class MyInteger:
def __init__(self, v):
self.data = v
def __repr__(self):
return 'MyInteger(%d)' % self.data
def __abs__(self):
'''此方法用于制定abs(obj) 函数取值时返回的结果'''
if self.data < 0:
# 用-self.data 创建一个新的对象返回回去
t = MyInteger(-self.data)
return t
return MyInteger(self.data)
def __len__(self):
'''len(obj) 函数规定只能返回整数值,
因此此方法不能返回字符串等其他类型的值'''
return 10
i1 = MyInteger(-100)
print(i1) # 等同于print(str(i1))
n = abs(i1)
print(n) # MyInteger(100)
print(len(i1)) # 等同于print(i1.__len__())
三、数值转换函数重载
__complex__ complex(obj) 函数调用
__int__ int(obj) 函数调用
__float__ float(obj) 函数调用
__bool__ bool(obj) 函数调用
四、布尔测试函数重载
用于bool(obj) 函数取值
用于if语句真值表达式中
用于while语句的值表达式中
重载方法
def __bool__(self):
...
说明
a、当自定义类内有__bool__(self) 方法时,以此方法的返回值作为bool(obj) 的返回值
b、当不存在__bool__ (self) 方法时,bool(x) 返回 __len__(self) 方法的返回值是否为零来测试布尔值
c、当再不存在__len__(self)方法时,则直接返回True
示例
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return "MyList(%s)" % self.data
def __len__(self):
print("__len__被调用")
return len(self.data)
def __bool__(self):
'''此方法用来制定一个bool(x) 返回的规则'''
# 如果没有任何元素返回False
print("__bool__方法被调用")
if len(self.data) == 0:
return False
for x in self.data:
if x:
return True
return False
myl = MyList([1, -2, 3, -4])
print(myl)
print(bool(myl)) # False
print(len(myl))
myl1 = MyList([0, 0.0, False, None])
print(bool(myl1)) # False
myl2 = MyList([0, 1, 2])
print(bool(myl2)) # True
五、迭代器(高级)
1、迭代器
可以通过next函数取值的对象就是迭代器
迭代器协议
迭代器协议是指对象能够使用next函数获取下一个数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定
迭代器的实现
通过__next__(self) 方法用来实现迭代器协议
重载方法
class MyIterator:def __next__(self):
迭代器协议
return 数据
2、可迭代对象
是指能用iter(obj) 函数返回迭代器对象可迭代对象内部要定义__iter__(self) 方法来返回迭代器对象
重写方法
class MyIterable:def __iter__(self):
语句块
return 迭代器
3、示例
指定迭代器
# 此示例示意用自定义的类MyRange实现可迭代对象
# 用自定义的类MyIterator 实现迭代器
class MyIterator:
def __init__(self, start, stop, step):
# self.start变量用来记录迭代器的起始位置和当前位置
self.start = start
self.stop = stop
self.step = step
def __next__(self):
'''此方法用于实现迭代器协议'''
print("MyIterator.__next__方法被调用!")
if self.start >= self.stop: # 迭失终止条件
raise StopIteration
r = self.start # 先将要返回的数存于变量r中
self.start += self.step # 迭代器后移
return r # 送回给next(it) 调用
class MyRange:
def __init__(self, start, stop=None, step=1):
if stop is None:
stop = start
start = 0
self.start = start # 起始值
self.stop = stop # 终止值
self.step = step # 步长
def __repr__(self):
return "MyRange(%d, %d, %d)" % (self.start,self.stop, self.step)
def __iter__(self):
'''此方法用于把MyRange类型创建的对象当做可迭代对象'''
print("__iter__被调用")
# 此处必须返回迭代器
return MyIterator(self.start, self.stop, self.step)
L = [x for x in MyRange(5, 10)]
print(L)
print('----------------------------')
R = MyRange(5, 10, 2)
it = iter(R) # R.__iter__
print(next(it)) # it.__next__
指定自身既是迭代器又是可迭代对象
# 此示例示意用自定义的类MyRange实现可迭代对象和实现迭代器
class MyRange:
def __init__(self, start, stop=None, step=1):
if stop is None:
stop = start
start = 0
self.start = start # 起始值
self.stop = stop # 终止值
self.step = step # 步长
def __repr__(self):
return "MyRange(%d, %d, %d)" % (self.start,self.stop, self.step)
def __iter__(self):
'''此方法用于把MyRange类型创建的对象当做可迭代对象'''
print("__iter__被调用")
return self
def __next__(self):
'''此方法用于实现迭代器协议'''
print("MyIterator.__next__方法被调用!")
if self.start >= self.stop: # 迭失终止条件
raise StopIteration
r = self.start # 先将要返回的数存于变量r中
self.start += self.step # 迭代器后移
return r # 送回给next(it) 调用
L = [x for x in MyRange(5, 10)]
print(L)
print('----------------------------')
R = MyRange(5, 10, 2)
it = iter(R) # R.__iter__
print(next(it)) # it.__next__
六、环境管理器
a、类内有__enter__方法 和 __exit__ 实例方法的类被称为环境管理器(也有叫上下文管理器)b、能够用with语句进行管理的对象必须是环境管理器
c、__enter__将在进入with语句时被调用,并返回由 as 变量绑定的对象
d、__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语句之外,也是程序的最后一条语句")
七、运算符重载
让自定义的类生成的对象(实例)能够实例运算符进行操作
作用
a、让自定义类的实例像内建对象一样进行运算符操作b、让程序简洁易读
c、对自定义的对象将运算符赋予新的运算规则
说明
运算符重载方法的参数已经有固定的含义,不建议改变原有的意义
1、算术运算重载
方法名 运算符和表达式 说明
__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) 右手边
二元运算符重载方法格式
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__方法被调用")
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)
1)反向算术运算符的重载
当运算符的左侧为内建类型时,右侧为自定义类型进行算术运算时,会出现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 冪运算
示例
class MyNumber:
def __init__(self, v):
self.data = v
def __repr__(self):
return "MyNumber(%d)" % self.data
def __sub__(self, rhs):
'''实现减法操作,生成一个新的对象并返回给调用者'''
print("__sub__方法被调用")
return MyNumber(self.data - rhs)
def __rsub__(self, lhs):
'''实现被减操作,生成一个新的对象并返回给调用者'''
return MyNumber(lhs - self.data)
n1 = MyNumber(100)
n2 = MyNumber(200)
n3 = n1 - 200 # 等同于n1.__sub__(200)
# n3 = n1.__sub__(200)
print(n1, "-200", '=', n3)
n4 = 600 - n2 # 等同于n2.__rsub__(600)
#n4 = n2.__rsub__(600)
print('n4 =', n4)
2)复合赋值算术运算符重载
以复合赋值算术运算符 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 冪运算
说明
a、如果__add__和__iadd__的方法不同(运算结果不同)的时候,x += x 和 x = x + x是不等价的,两者得到的结果是不同的,其他复合运算同理
b、如果__add__和__iadd__同时存在,复合运行优先采用__iadd__方法
c、如果__iadd__不存在,复合运行采用__add__方法
d、如果__add__和__iadd__均存在,运行报错
示例
# 此示例示意复合赋值算术运算符的重载
class YouList:
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 YouList(self.data + rhs.data)
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([100])
L1 += L1 # __iadd__方法被调用
print('L1 =', L1)
L2 = YouList([100])
L2 += L2 # __add__方法被调用
print('L2 =', L2)
2、比较运算符的重载
方法名 运算符和表达式 说明__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
3、位运算符的重载
方法名 运算符和表达式 说明__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, 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 右移
4、一元运算符的重载
方法名 运算符和表达式 说明__neg__(self) - self 负号
__pos__(self) + self 正号
__invert__(self) ~ self 取反
重载方法
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):
'''规则是正变负,负变正'''
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 成员运算
示例
# 此示例示意一元运算符的重载
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内")
if 4 not in L1:
print('4 不在L1内')
5、索引和切片运算符的重载
1) [ ]索引切片
重载方法 运算符和表达式 说明__getitem__(self, i) x = self[i] 索引/切片取值
__setitem__(self,i,val) self.[i]=val 索引/切片赋值
__delitem__(self, i) del self[i] del语句索引/切片
作用
让自定义的类型的对象能够支持索引和切片操作
示例
# 此示例示意[]运算符的重载
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
def __delitem__(self, i):
del self.data[i]
L1 = MyList([1, -2, 3, -4, 5])
x = L1[0] # L1.__getitem__(0)
print(x)
L1[1] = 2 # L1.__setitem__(1, 2)
print(L1)
print(L1[0:5:1]) # 切片读取列表
L1[::] = [] # 删除 列表中值
print(L1)
2)slice 构造函数
用于创建一个slice切片对象,此对象存储一个切片起始值,终止值,步长值信
格式
slice(start=None, stop=None, step=None) 创建 一个slice 切片对象slice 对象属性
s.start 切片的起始值
s.stop 切片的终止值
s.step 要片的步长
示例
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功能(实现魔法函数)
作用
a、用来模拟一个属性b、通过@property装饰器可以对模拟的属性赋值和取值加以控制
示例
# 此示例示意特性属性的用法
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) # ...
# 此示例示意特性属性的用法
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) # ...