#__init__ 构造方法,双下划线 #__del__ 析构方法,在对象就要被垃圾回收前调用。但发生调用 #的具体时间是不可知的。所以建议尽量避免使用__del__ print('-------example1') class A: def __init__(self): self.a='a' def printA(self): print(self.a) class B(A): def __init__(self): #A.__init__(self) 未绑定方法,自由提供self参数 #super(B, self).__init__() self.b='b' def printB(self): print(self.b) b=B() try: b.printA() #注释后,没有.a属性 except Exception as e: print(e) #B继承A后,构造方法覆盖了A的构造方法,所以b.printA()没有self.a的属性。 #旧版python 方法:加上注释的未绑定方法就好 #新式类方法:注释的super 方法。先继承会覆盖后继承 print('-------example2') class A: def __init__(self): self.chr='a' def printA(self): print(self.chr) class AA: #继承没有 def __init__(self): A.__init__(self) #未绑定方法 def printAA(self): print(self.chr) aa=AA() aa.printAA() #得到 a (不继承A也可以调用A的构造函数?要用printA就要继承) print('-------example3') #super 的多继承 #即使类已经继承多个超类,它也只需要使用一次super函数(但要保证所有的超类的构造方法都使用了super) #super(TYPE, self).method调用的是mro列表中第一个,也即继承列表第一个类的方法。这个没有举例 class A: def __init__(self): self.a='a' def printA(self): print(self.a) class B: def __init__(self): self.b='b' def printB(self): print(self.b) class C(A,B): def __init__(self): super(C,self).__init__() self.c='c' def printC(self): print(self.c) c=C() c.printA() try: c.printB() #报错,没有.b属性 except Exception as e: print(e) #解决方法,在所有超类里使用super。只在B中使用super还是不行 class A: def __init__(self): super(A, self).__init__() self.a='a' def printA(self): print(self.a) class B: def __init__(self): super(B, self).__init__() self.b='b' def printB(self): print(self.b) class C(A,B): def __init__(self): super(C,self).__init__() self.c='c' def printC(self): print(self.c) print('-------example4') #实现序列,映射 #__len__(self), __getitem__(self,key), __setitem__(self,key,value), __delitem__(self,key) #定义后相应用len(obj),obj[key],obj[key]=value,del obj[key] #当为一个序列,key键应该是一个整数(自己写函数检查)。对映射,可以使用任何种类的键。例子P144 #继承标准库的UserList,UserString,UserDict的上面方法 class CountList(list): def __init__(self,*args): super(CountList,self).__init__(*args) self.count=0 def __getitem__(self,index): self.count+=1 return super(CountList,self).__getitem__(index) c=CountList(range(10)) c.reverse() print(c) del c[3:5] print(c) print(c.count) print(c[2]+c[5]) print(c.count) print('-------example5') #property函数,统一处理类的多个属性,实现get,set,del操作。不需要为每一个属性写一个处理方法了 #绑定del 函数,可以使用 del t.all 语句 class Test: def __init__(self): self.a=0 self.b=0 def setAll(self, size): self.a, self.b=size def getAll(self): return self.a, self.b all=property(getAll,setAll) #property中函数setAll的参数size #要与property返回的all一样是一个元组 t=Test() t.all=1,2 #只有property 中绑定了setAll函数才可以赋值 print(t.all) print(t.a) print('-------example6') #静态方法staticmethod,类成员方法classmethod class A: @staticmethod def smethod(): print('smethod') def cmethod(cls): print('classmethod') A.smethod() A.cmethod(A) #这里有问题, 需要有时间查资料 print('-------example7') #__getattribute__(self,name) __getattr__(self,name)__ #__setattr__(self,name,value) __delattr__(self,name)__ P151 #__getattribute__特殊方法,用于查询任意属性。 #__getattr__只能用来查询不在__dict__系统中的属性 #定义__getattribute__后,命令行输入a.后,不会有a的属性、方法的提示了 #定义__getattr__ 不会有这种情况 #当我们查询一个属性时,如果通过__dict__方法无法找到该属性, #那么Python会调用对象的__getattr__方法,来即时生成该属性 class A: def __init__(self): self.a=0 self.b=0 def __setattr__(self,name,value): if name=='size': self.a,self.b=value else: #这里换成self.name=value时,a=A()为什么会死循环 self.__dict__[name]=value def __getattr__(self,name): if name=='size': return self.a,self.b else: raise AttributeError a=A() a.size=1,2 a.size try: a.c except Exception as e: print(e) #拓展1 setattr(a,'d',3) print(a.__dict__) #多了变量d delattr(a,'d') print(a.__dict__) #少了变量d print('-------example8') #拓展2 class C(object): a = 'abc' def __getattribute__(self, *args, **kwargs): print("__getattribute__() is called") return object.__getattribute__(self, *args, **kwargs) def __getattr__(self, name): print("__getattr__() is called ") return name + " from getattr" def __get__(self, instance, owner): print("__get__() is called", instance, owner) return self def foo(self, x): print(x) class C2(object): d = C() c = C() c2 = C2() c.a #__getattribute__() is called c.zzzzzz #__getattribute__() is called, __getattr__() is called c2.d #__get__() is called <__main__.C2 object at 0x026AAB30> <class '__main__.C2'> #<__main__.C object at 0x026AAAB0> c2.d.a #__get__() is called <__main__.C2 object at 0x026AAB30> <class '__main__.C2'> #__getattribute__() is called #每次通过实例访问属性,都会经过__getattribute__函数。而当属性不存在时, #仍然需要访问__getattribute__,不过接着要访问__getattr__。这就好像是一个异常处理函数。 #每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。 #object.__get__(self, instance, owner) #如果class定义了它,则这个class就可以称为descriptor。 #owner是所有者的类,instance是访问descriptor的实例,如果不是通过实例访问, #而是通过类访问的话,instance则为None。 #(descriptor的实例自己访问自己是不会触发__get__,而会触发__call__, #只有descriptor作为其它类的属性才有意义。)(所以下文的d是作为C2的一个属性被调用) print('-------example9') #自己问题例子 class Test: def __init__(self): self.a=0 self.b=0 def setAll(self, size): self.a, self.b=size def getAll(self): return self.a, self.b def __getattribute__(self,name): if name=='size1': return self.a,self.b elif name=='a': #return self.a #加上这句,调用t.a 就会死循环,这个一直进入自己 #return self.__dict__['a'] #报'NoneType' object is not subscriptable print('a visited') return object.__getattribute__(self,name)#加这句可以 elif name=='b': print('b visited') def __getattr__(self,name): if name=='size2': print('size2 visited') return self.a,self.b else: raise AttributeError def __setattr__(self, name, value): if name=='a': print('a is changed') elif name=='b': print('b is changed') elif name=='all': print('all changed') all=property(getAll,setAll) t=Test() try: t.getAll() #出错,NoneType object is not callable, setAll也是这个错。 #__getattribute__加上return后不会有问题 except Exception as e: print(e) try: t.size1 #为什么返回None, None。因为__getattribute__在访问a,b时没有返回a,b的值 except Exception as e: print(e) print('-------example10') #__dict__属性 #__dict__分层存储属性。每一层的__dict__只存储该层新增的属性。 #子类不需要重复存储父类中的属性。 class bird(object): '__doc__ test' feather = True class chicken(bird): fly = False def __init__(self, age): self.age = age summer=chicken(2) print(bird.__dict__) print(chicken.__dict__) print(summer.__dict__) print(summer.__dict__['age']) b=bird() print(b.__dict__) #这个是空{} feather属性存储在bird.__dict__中 print('-------example11') #迭代器,实现__iter__(返回一个迭代器)和__next__方法 #如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常 class Fibs: def __init__(self): self.a=0 self.b=1 def __next__(self): self.a,self.b=self.b,self.a+self.b return self.a def __iter__(self): return self fibs=Fibs() for f in fibs: if f>1000: print(f) break #从可迭代对象中获得迭代器 it=iter([1,2]) print(it.__next__()) #1 print(it.__next__()) #2 try: print(it.__next__()) #StopIteration except Exception as e: print(e) #把迭代器转换成序列 class Test(): value=0 def __next__(self): self.value+=1 if self.value>10:raise StopIteration # return self.value def __iter__(self): return self t=Test() print(list(t)) # print('-------example12') #生成器,用函数语法定义的迭代器。任何包含yield语句的函数称为生成器 #他不是像return那样返回值,而是每次产生多个值 #生成器方法:send,throw,close #在生成器close方法被调用后再通过生成器生成一个值会导致RuntimeError def repe(value): for i in value: yield i value=[i*2 for i in range(10)] print(value) #0~18 r=repe(value) try: print(r.send('a')) #TypeError: can't send non-None value to a just-started generator except Exception as e: print(e) print(r.__next__()) #r.send(None) 返回0,第一个数 print(r.send('a')) #返回2,第2个数 for i in r: print(i) #从第3个数4开始到结束 try : print(r.send('a')) #报错,StopIteration except Exception as e: print(e) #生成器推导式,返回的不是列表而是生成器 g=(i*2 for i in range(2,10)) #圆括号,不是方括号 print(g.__next__()) #4 #send方法 #只有在生成器挂起后才有意义(也就是说在yield第一次被执行后)。即调用一次next__后 #如果真想对刚刚启动的生成器使用send方法,可以将None作为参数进行调用 def repe(value): while True: yield value r=repe(4) print(r.send(None)) #返回4 print(r.send('a')) #返回4 def repe(value): while True: new=yield value print('new:',new,'value:',value) if new is not None:value=new r=repe(4) print(r.send(None)) #返回4 print(r.send('a')) #返回a new=a,value=4 print(r.send('aa')) #返回aa new=aa,value=a