下面包含了
__getitem__,__iter__ , __next__,__contains__,他们的优先级,以及__getitem__的通用性
__getattr__ , __setattr__ , __getattribute__, __call__ , __del__
说明:
在python的所有可迭代环境中, __iter__ 是优先级最高的, 如果没有__iter__ ,则尝试使用__getitem__. 除了使用[]运算符 ,会直接调用__getitem__
简介:
__getitem__ : 应用于[] , 迭代(for 循环, in 操作符, 列表解析,多元赋值)
__iter__ :返回一个迭代器 , 当调用iter(obj) 会调用 obj.__iter()
__next__ : 返回迭代器产生的值, 与__iter__ 一起使用 ,应用于迭代
__contains__:作用于 in操作符
__getattr__ :当对象本身及其所有父类的属性都找过却没有找到时调用
__setattr__ : 改变了对象属性的赋值过程,例如 obj.attr=value => obj.__setattr__(attr,value)
__getattribute__: 拦截了对象的获取过程 ,例如 obj.attr => obj.__getattribute__(attr)
__call__ : 使对象可以像函数一样可以被调用 ; 实际上,def func() 普通函数就是一个对象实现了__call__
__del__ :析构函数, python中并不那么常用
1.__getitem__ :可以用于索引,分片,迭代. (in 也是一种迭代)
#用于索引,分片
class Index:
data = [1,2,3,4,5]
def __getitem__(self, item):
print("__getitem__:",item)
return self.data[item]
index = Index()
print(index[0],index[-1])
print(index[1:3])
#__getItem__ 一种重载迭代的方式
class Stepper:
data = "rain over me"
def __getitem__(self, item):
print("__getitem__ -> item:%s "%item)
return self.data[item]
s = Stepper()
for i in s:
print(i,end=',')
#与迭代相关的都能支持 ,内部一致调用__getitem__
print('m' in s)
print([x for x in s])
2.__iter__ 与 __next__
python中的迭代环境首先会尝试 iter() => __iter()__ 方式来迭代 , 如果类中没有写__iter()__ 会再尝试__getitem()__
__iter__的优先级要高于__getitem__
函数iter() 会调用类中的__iter__ 返回一个迭代器 ,在迭代过程中会调用next(obj) 相当于 obj.__next__()
下面是一个只能支持单次循环的迭代器 , 即当迭代完成时,就无法再次迭代了
#一个简单的迭代器,返回平方
class Test:
def __init__(self,start = 1, stop = 3):
self.index = start - 1
self.stop = stop
def __iter__(self): #返回自身作为迭代器
return self
def __next__(self): #调用iter()后需要实现一个__next__ 函数, 用于迭代中(next(obj) 相当于 obj.__next__)
if self.index == self.stop:
raise StopIteration
self.index += 1
return self.index ** 2
t = Test()
for i in t: #for 内部会调用iter() 来产生一个迭代器,这里迭代器是自身
print(i,end=',') #每一次循环会调用t.__next__()
print("无法再次迭代了:",[value for value in t]) #只能迭代一次,原因是当调用__next__时 self.index == self.stop
下面是一个支持多个迭代器的一种方式:
#单独写一个用于__next__的类
class multiIterator:
def __init__(self,value):
self.value = value
self.offset = 0
self.len = len(value)
def __next__(self): #重点在__next__,在迭代过程中会不断的调用 obj.__next__()
if self.offset < self.len:
item = self.value[self.offset]
self.offset += 1
return item
else:
raise StopIteration
class multiObject:
def __init__(self,value):
self.value = value
def __iter__(self): #支持多个迭代器的重点,不再返回自身,而是新创建一个迭代器
return multiIterator(self.value)
l = [1,2,3,4,5]
m = multiObject(l)
iter_m = iter(m) #调用m.__iter__() 返回一个新的迭代器
print(next(iter_m),next(iter_m),end=' ') #next 接受一个迭代器
print("\n")
#一次新的迭代
for obj in m: #for 会调用 iter(obj) 返回一个迭代器, 然后 obj = next(迭代器)
print("in for",obj)
in 用于__getitem__,__iter__ , __next__,__contains__ , 优先级为 contains > iter > getitem
class TestIter:
data = '1234567'
def __getitem__(self, item):
print("__getitem__:", item)
return self.data[item]
# def __iter__(self):
# print("__iter__")
# self.index = 0 #自身作为迭代,进行初始化,用于后面__next__的调用
# self.len = len(self.data)
# return self
# def __next__(self):
# print("__next__")
# if self.index == self.len: #如果取完数据抛出异常StopIteration
# raise StopIteration
# else:
# value = self.data[self.index]
# self.index +=1
# return value
# def __contains__(self, item):
# print("__contains__")
# return item in self.data
t = TestIter()
print('2' in t)
输出:
__getitem__: 0
__getitem__: 1
True
把__iter__ 以及 __next__ 取消注释后:
__iter__
__next__
__next__
True
__contains__ 取消注释后:
__contains__
True
3.__getattr__ 当obj.attr 在实例,所有父类中都无法找到时,将会调用 __getattr__函数
class SomeClass:
def __getattr__(self, item):
if item == "hola": #可以自定义一些属性
return 100
else:
raise AttributeError(item)
s = SomeClass()
print(s.hola)
4. __setattr__ : 影响了对象的赋值过程,如果在类中定义了
那么obj.attr = value => obj.__setattr__(attr,attrValue)
class SomeClass:
def __getattr__(self, item):
if item == "hola": #可以自定义一些属性
return 100
else:
raise AttributeError(item)
def __setattr__(self, key, value):
if key == 'hello':
self.__dict__[key] = value #在里面不能再次使用self.key = value ,这样会又一次调用__setattr__,无穷递归;
else:
raise AttributeError(str(key) +"无法赋值")
s = SomeClass()
s.hello = 100
特别注意的是在内部不能使用self.attr = value ,只能使用对象词典赋值
5.__getattribute__ : 作用于所有obj.attr 的取值 , 而__getattr__是当实例本身,以及所有父类都无法找到时再次调用
class GetAttribute:
def __getattribute__(self, item):
print("无法取得任何值")
g = GetAttribute()
g.x = 100
print(g.x)
#输出:
无法取得任何值
None
6. __call__ : python中的普通函数 就是一个函数对象, __call__ 让这件事情开始明朗了,就像定义常规函数一样对待__call__
#在python中函数就是一个对象
class CallClass:
def __init__(self):
print("__init__")
def __call__(self, *args, **kwargs): #__call__(参数随便填写,出了第一个self)
print("__call__ :" ,args,kwargs)
c = CallClass()
c(1,2,3)
7. __del__ :动态语言中并不常用 , C++用的比较多
class Dest:
def __del__(self):
print("我被释放了")
d = Dest()
d = "hh"
当Dest() 这个对象没有变量引用的时候, 垃圾回收(gc) 会自动回收这个对象