2017年4月25日 python 之__setitem__,__getitem,__delitem__等属性
__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']=18 f['age1']=19 print(f['age']) print(f.age1) del f.age1 del f['age'] print(f.__dict__)
__slots__:
#使用类.xxx,或者对象.xxx,来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的字典是独立的) #字典会占用大量的内存,如果有一个属性很少的类,但是实例很多的类,用__slots__来代替__dict__,限制对象属性数量,对所有对象属性统一管理, #节省内存.缺点是不能再给实例添加新属性,只能用里面有的。 class People: __slots__ = ['x','y','z'] p=People() p.x=10 p.y=20 p.z=30 print(p.x,p.y,p.z)
利用__iter__和__next__实现迭代器和range():
#实现迭代器协议 from collections import Iterable,Iterator class Foo: def __init__(self,start): self.start=start def __iter__(self): return self def __next__(self): n=self.start self.start+=1 return n f=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 n for i in Range(3, 8): print(i)
__doc__:描述文档
class Foo: '我是class描述信息' pass print(Foo.__doc__) #输出:我是class描述信息
#该属性无法继承给子类
def Func(): '我是def描述信息' pass print(Func.__doc__) #输出:我是def描述信息
__del__:析构方法
# 析构方法___del__析构方法,当对象在内存中被释放时,自动触发执行。 # 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放, # 因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。 #垃圾回收机制,del 立即删除,不然等其他执行完毕,自动回收 import time class 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): # pass p=People("ada") print(callable(People)) #True print(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): pass print(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)) # 运行结果: # <class 'type'> # <class '__main__.Bar'> # <class 'type'> # <class 'str'> # <class 'int'>
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样
元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
创建类的两种方式:
# 创建类的两种方式 # 方式一: class Foo: def func(self): print('from func') # 方式二: x = 1 def 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 obj class 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->obj Mymeta()触发type.__call__ Foo()触发Mymeta.__call__ obj()触发Foo.__call__ 2.__call__内按先后顺序依次调用儿子的__new__和__init__方法 '''