python类杂项
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返回了一个生成器对象)