OOP:Object Oriented Programming (面向对象编程)
oop就是在树中搜索属性和在函数中加入一个特殊的第一位参数self,它特殊在于总是接收作为方法调用隐含主体的实例对象
类树搜索顺序:从下到上,从左到右
使用实例属性时自动将这个实例对象传给参数self,self是进入实例对象命名空间的钩子
当给self赋值或修改时只会在实例内赋值修改,不会爬类树;而引用属性,且当实例中没有这个属性时则会爬类树寻找
python惯例类名以大写字母开头,模块名用小写字母开头
class规则是LEGB只会搜索def,模块和内置定义的变量
#one.py class A: data = 999 #在其他类(非子类)要调用data必须使用A.data #类初始化 def __init__(self,val): self.data = val self.b = B #符号重载 #加号 def __add__(self,other): return A(self.data+other) #左加法:self+other(a+3,a传给self,3传给other) def __radd__(self,other): return A(other+self.data) #右加法:other+self(3+a) def __iadd__(self,other): self.data += other #原位置加法 return self #字符串,打印 def __str__(self): return 'A class: %s'% self.data def __repr__(self): return 'A:%s'%self.data #索引和分片 def __getitem__(self,index): return index**2 #当调用X[i]时会将X作为第一个参数传入,将i作为第二个参数传入 #拦截未定义属性的访问,转到B类中查找属性(不拦截赋值运算) def __getatrr__(self,attr) return getattr(self.b,attr) #拦截所有属性赋值并输出错误提示 def __setattr__(self,attr,value): raise AttributeError(attr+'not allow') #所有的a.data = 0形式的语句都会被拦截 #类方法 def setdata(self,newdata): self.data = newdata def show(self): print(self.data) #当类方法第一个参数不是self是需要直接用类调用 def display(): print("class A display") #调用方法:A.display() #类继承 class B(A): #子类中的setdata方法会覆盖父类中的setdata,子类的实例对象可以用父类中的show方法 def setdata(self,val): self.data = val #two.py #模块获取类 import one a = one.A() #查看实例可访问的属性 a.__dict__ #查看实例对象对应的类 x.__class__ #查看父类对象引用的元组,object是根类 A.__bases__ #顶层脚本测试 if __name__ == '__main__': #test code #读取文档 a.__doc__
当调用x[i]时x会 ' [ ] ' 调用 getitem(self,index) 方法,将x传入第一个参数,i 传入第二个参数
当调用x[1:4]时[ ] 会调用getitem(self,index) 方法, ' : ' 会调用slice(index1,index2)方法将1传入index1,4传入index2,再将slice(1,4)传入getitem中的index
#区分index类型 class Indexer: def __getitem__(self,index): if isinstance(index,int): print('indexing') #若index为整数则打印indexing else: print('slicing',index.start,index.stop,index.step) #如果index是分片对象打印slcing,起始位置,结束位置和步长
Python中的迭代上下文会先尝试__iter__f方法(将可迭代对象传给iter),再尝试__getitem__. 只要是__iter__方法返回的都将被视为迭代器对象,可通过不断调用next方法产生元素直到Stopiteration异常出现
yield(生成器函数,将生成的数据放到内存中,返回的指针指向第一个数据的位置),返回一个新的生成器对象自动记录局部作用域和代码位置没有next方法,iter返回它本身有next方法
#单重迭代 class Object1: def __init__(self,wrapped): self. wrapped= wrapped self.offset = 0 def __iter__(self): return self def __next__(self): if self.offset >= len(self.wrapped): raise StopIteration else: item = self.wrapped[self.offset] self.offset += 1 return item #多重迭代 class Object2: def __init__(self,wrapped): self.wrapped = wrapped def __iter__(self): return Iterator(self.wrapped) class Iterator: def __init__(self,wrapped): self.wrapped = wrapped self.offset = 0 def __next__(self): if self.offset >= len(self.wrapped): raise StopIteration else: item = self.wrapped[self.offset] self.offset +=1 return item #iter 加 yield 可支持多重迭代 class Object3: def __init__(self,wrapped): self.wrapped = wrapped def __iter__(self): for i in range(len(self.wrapped)): yield self.wrapped[i] if __name__ == "__main__": str = "abc" I1 = Object1(str) I2 = Object2(str) I3 = Object3(str) for x in I1: for y in I1: print(x+y) #结果为ab ac for x in I2: for y in I2: print(x+y) #结果为aa ab ac ba bb bc ca cb cc(iter替迭代器定义了一个新的状态对象) for x in I3: for y in I3: print(x+y) #结果为aa ab ac ba bb bc ca cb cc(iter返回了一个生成器对象)