python运算符重载,魔术方法,索引,迭代,分片

下面包含了

 __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) 会自动回收这个对象

你可能感兴趣的:(py)