__setitem__,__getitem,__delitem__
#以字典格式操作对象的属性class Foo: def __init__(self,name): self.name=name def __getitem__(self, item): print(self.__dict__[item]) def __setitem__(self, key, value): self.__dict__[key]=value def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) def __delattr__(self, item): print('del obj.key时,我执行') self.__dict__.pop(item)f=Foo("adamander")print(f.name)print(f['name'])f['age']=18f['age1']=19print(f['age'])print(f.age1)del f.age1del f['age']print(f.__dict__)
__slots__:
#使用类.xxx,或者对象.xxx,来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的字典是独立的)#字典会占用大量的内存,如果有一个属性很少的类,但是实例很多的类,用__slots__来代替__dict__,限制对象属性数量,对所有对象属性统一管理,#节省内存.缺点是不能再给实例添加新属性,只能用里面有的。class People: __slots__ = ['x','y','z']p=People()p.x=10p.y=20p.z=30print(p.x,p.y,p.z)
利用__iter__和__next__实现迭代器和range():
#实现迭代器协议from collections import Iterable,Iteratorclass Foo: def __init__(self,start): self.start=start def __iter__(self): return self def __next__(self): n=self.start self.start+=1 return nf=Foo(0)print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))#一直不停的往下加# for i in f:# print(i)
# 实现range()class Range: def __init__(self,start,end): self.start=start self.end=end def __iter__(self): return self def __next__(self): if self.start==self.end: raise StopIteration n=self.start self.start+=1 return nfor i in Range(3, 8): print(i)
__doc__:描述文档
class Foo: '我是class描述信息' passprint(Foo.__doc__)#输出:我是class描述信息
#该属性无法继承给子类
def Func(): '我是def描述信息' passprint(Func.__doc__)#输出:我是def描述信息
__del__:析构方法
# 析构方法___del__析构方法,当对象在内存中被释放时,自动触发执行。# 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,# 因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。#垃圾回收机制,del 立即删除,不然等其他执行完毕,自动回收import timeclass Open: def __init__(self,filename,mode='r',encoding='utf-8'): self.file=open(filename,mode,encoding=encoding) def __enter__(self): print("enter=====>") return self def write(self,line): t=time.strftime('%Y-%m-%d %T') self.file.write('%s %s' %(t,line)) def __getattr__(self, item): return getattr(self.file,item) def __del__(self): print("===>del") def __exit__(self, exc_type, exc_val, exc_tb): # print("exit") # print("exc_type",exc_type) # print("exc_val",exc_val) # print("exc_tb",exc_tb) self.file.close()with Open('b.txt','w+') as f: f.write("xxxx") f.write("xxxx") f.write("xxxx")
__call__:是否可调用
# __call__实例调用,没有他,实例是不可调用的class People: def __init__(self,name): self.name=name # def __call__(self, *args, **kwargs): # passp=People("ada")print(callable(People)) #Trueprint(callable(p))#False,然而放开注释就是True
__enter__和__exit__:
# with open('a.txt') as f:# '代码块'# 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法class Open: def __init__(self,name): self.name=name def __enter__(self): print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量,即f') # return self def __exit__(self, exc_type, exc_val, exc_tb): print('当with中代码块执行完毕时执行我')with Open('a.txt') as f: print('=====>执行代码块') # print(f,f.name) # 运行结果:# 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量,即f# =====>执行代码块# 当with中代码块执行完毕时执行我
metaclass 元类:
# typer===>produce class===>produce obj# type称谓元类,是所有类的类,利用type控制类的行为, 模拟class关键字创建类的过程class Foo: x=1 def run(self): passprint(type(Foo))class_name="Bar"def Run(self): print("%s is running"%self.name)bases=(object,)class_dic={ "x":1, "run":Run}Bar=type(class_name,bases,class_dic)print(Bar)print(type(Bar))print(type("123"))print(type(123))# 运行结果:## # # #
元类是类的类,是类的模板元类是用来控制如何创建类的,正如类是创建对象的模板一样元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
创建类的两种方式:
# 创建类的两种方式# 方式一:class Foo: def func(self): print('from func') # 方式二:x = 1def func(self): print('from func') Foo=type('Foo',(object,),{ 'func':func,'x':1})
#利用元类来设计一个类,要求类内的函数必须写注释class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): for key in class_dic: if not callable(class_dic[key]):continue if not class_dic[key].__doc__: raise TypeError("all the func must be notes")class Foo(metaclass=Mymeta): x=1 def run(self): '所有函数必须写注释' print("class Foo")Foo()
终极:盗墓笔记的终极
#元类总结class Mymeta(type): def __init__(self,name,bases,dic): print('===>Mymeta.__init__') def __new__(cls, *args, **kwargs): print('===>Mymeta.__new__') return type.__new__(cls,*args,**kwargs) def __call__(self, *args, **kwargs): print('aaa') obj=self.__new__(self) self.__init__(self,*args,**kwargs) return objclass Foo(object,metaclass=Mymeta): def __init__(self,name): self.name=name def __new__(cls, *args, **kwargs): return object.__new__(cls)'''需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__而爹.__call__一般做两件事:1.调用name.__new__方法并返回一个对象2.进而调用name.__init__方法对儿子name进行初始化''''''class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行Foo=Mymeta('foo',(...),{...})因此我们可以看到,只定义class就会有如下执行效果===>Mymeta.__new__===>Mymeta.__init__实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化''''''obj=Foo('egon')的原理同上''''''总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了1.谁后面跟括号,就从谁的爹中找__call__方法执行type->Mymeta->Foo->objMymeta()触发type.__call__Foo()触发Mymeta.__call__obj()触发Foo.__call__2.__call__内按先后顺序依次调用儿子的__new__和__init__方法'''