#1.
#A:运算符重载只是意味着在类方法中拦截内置的操作,当类的实例出现在内置操作中,python会自动调用重载的方法
#B:__init__构造函数是最常见的运算符重载
#2.
#A:常见的运算符重载方法:
'''
__init__ 构造函数
__del__ 析构函数
__add__ +
__or__ |
__repr__, __str__ 打印,转换
__call__ 函数调用
__getattr__ 点号运算
__setattr__ 属性赋值语句 X.any = value
__delattr__ 属性删除 del X.any
__getattribute__ 属性获取 X.any
__getitem__ 索引运算
__setitem__ 索引赋值
__delitem__ 索引和分片删除 del X[key] X[i:j] = sequence
__len__ 长度
__It__, __gt__, __le__, __ge__, __eq__, __ne__ X < Y, X > Y, X <= Y, X >= Y, X == Y, X != Y
__radd__ 右侧加法 other + X
__iadd__ 增强加法 X += Y
__iter__, __next__ 迭代环境
__contains__ 成员关系测试
__index__ 整数值
__get__, __set__ 描述符属性
__delete__, __new__ 创建和删除
__sub__ 减法
__enter__, __exit__ 环境管理器
'''
#3.
#A:一些内置的操作,如打印,有默认的重载方法,继承于python3.0中隐含的object类中
#4.
#A:索引和分片:__getitem__, __setitem__
#B:除了索引,对于分片表达式也调用__getitem__
#C:__getitem__也可以是python中一种重载迭代的方式
class CTest():
L0 = [1, 2, 3]
def __getitem__(self, index):
print(index)
return CTest.L0[index]
def __setitem__(self, index, value):
print(index)
CTest.L0[index] = value
Test = CTest()
value = Test[0] #value = 1 输出0
Test[0] = 'a' #输出0
value = CTest.L0 #value = ['a', 2, 3]
value = Test[0:2] #value = ['a', 2] 输出slice(0, 2, None)
Test[0:2] = 'abc'
value = Test.L0 #value = ['a', 'b', 'c', 3] 输出slice(0, 2, None)
L0 = []
for value in CTest():
L0.append(value) #L0 = ['a', 'b', 'c', 3] 输出0\n1\n2\n3\n4\n
#5.
#A:尽管__getitem__能在迭代环境中使用,但是这只是退而求其次的方法
#B:python中的迭代环境都会先尝试__iter__方法,再尝试__getitem__
#C:迭代环境是通过调用内置函数iter去尝试寻找__iter__方法来实现的,而这种方法应该返回一个迭代器对象
# 如果提供了,python就会重复调用这个迭代器对象的next方法,直到发送StopIterator异常
# 如果没找到这类的__init__方法,python就会改用__getitem__机制,直到发生IndexError异常
class CTest():
count0 = 0
count1 = 0
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self):
CTest.count0 += 1
return self
def __next__(self):
CTest.count1 += 1
if self.start == self.stop:
raise StopIteration
else:
self.start += 1
return self.start ** 2
Test = CTest(0, 5)
L0 = []
for value in Test:
L0.append(value) #L0 = [1, 4, 9, 16, 25]
value = CTest.count0, CTest.count1 #value = (1, 6)
try :
value = next(Test)
except StopIteration:
pass #运行至此
#对于上述类,一个类实例的迭代器只有一种状态,可以创建一个类,其实例的迭代器有多个状态
class CIter():
def __init__(self, value):
self.value = value
self.start = 0
def __next__(self):
if self.start == len(self.value):
raise StopIteration
else:
value = self.value[self.start]
self.start += 1
return value
class CTest():
def __init__(self, value):
self.value = value
def __iter__(self):
return CIter(self.value)
Test = CTest("abc")
L0 = []
for i in Test:
for j in Test:
L0.append(i + j) #L0 = ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']
#对于这个类,一个类的实例可以拥有多个状态
#6.
#A:运算符重载往往是多个层级的:类提供特定的方法或者提供退而求其次的更通用的替代方案
# 布尔测试会先尝试一个特定的__bool__,如果没有则会尝试__len__
class CTest():
def __init__(self, value):
self.value = value
def __bool__(self):
return bool(self.value)
def __len__(self):
return len(self.value)
def __contains__(self, value):
return value in self.value
Test = CTest('abc')
b0 = bool(Test) #b0 = True
v0 = len(Test) #v0 = 3
b1 = 'b' in Test #b1 = True
#7.
#A:__getattr__方法是拦截属性点号运算的,当类实例使用点号访问未定义属性的时候就会调用此方法,若访问的属性在继承树中存在则不会调用
#B:__setattr__方法会拦截所有属性的赋值语句,在此函数中对self进行赋值会导致无限递归,所以要使用实例的属性字典进行赋值
#C:可以利用__setattr__来对属性赋值进行拦截,来防止在类外部对类实例的属性进行更改,从而达到类似于属性的private属性
class CTest():
def __init__(self):
self.value = 'abc'
def __getattr__(self, str):
print(str + " is not exist")
def __setattr__(self, str, value):
#self.str = value 会导致无限循环
self.__dict__[str] = value + '__setattr__'
Test = CTest()
Test.value #并不会产生输出
Test.str #输出str is not exist
Test.value = 'szn'
v0 = Test.value #v0 = 'szn__setattr__'
b0 = 'str' in Test.__dict__ #b0 = False
Test.str = 'str'
b1 = 'str' in Test.__dict__ #b1 = True
#8.
#A:__getattribute__方法会拦截所有的属性获取,而非仅仅是未定义的,此方法很容易导致无限递归
#B:__getattribute__中要用object,不然会陷入无穷递归
class CTest():
def __init__(self):
self.value = 'abc'
def __getattribute__(self, str):
if 'value' == str:
return object.__getattribute__(self, str)
else:
return str
Test = CTest()
v0 = Test.str #v0 = 'str'
v1 = Test.value #v1 = 'abc'
#9.
#A:打印操作会首先尝试__str__然后尝试__repr__
#B:__str__, __repr__都必须返回字符串,其他结果类型不会转换并会引发错误
class CTest():
def __repr__(self):
return 'repr'
Test = CTest()
str0 = str(Test) #str0 = 'repr'
str1 = repr(Test) #str1 = 'repr'
class CTest():
def __str__(self):
return 'str'
Test = CTest()
str0 = str(Test) #str0 = 'str'
str1 = repr(Test) #str1 = '<__main__.CTest object at 0x0000000002E3B630>'
#10.
#A:__radd__右侧加法, __iadd__增强加法, __add__加法
#B:当两个类实例相加时,先调用__add__,然后通过简化左边的运算数来除法__radd__
#C:每个二元运算都有类似的右侧和原处重载方法
class CTest():
def __init__(self):
self.str = ''
def __add__(self, value):
print('a')
return self.str + value
def __iadd__(self, value):
print('i')
self.str += value
return self
def __radd__(self, value):
print('r')
return self.str + value
Test = CTest()
v0 = Test + 'a' #v0 = 'a' 输出a
v1 = 'b' + Test #v1 = 'b' 输出r
Test += 'c' #输出i
s0 = Test.str #s0 = 'c'
v2 = CTest() + CTest() #v2 = '' 输出a\nr
#11.
#A:__call__函数调用运算符
#B:__del__析构函数
class CTest():
def __call__(self, str):
return str
def __del__(self):
print("del\n")
Test = CTest()
str = Test('a') #str = 'a'
Test = 'a' #输出del