Python高级部分(一)
一 元类
1.1 什么是元类?
①元类是类的类,是类的模板;
②元类是用来控制如何创建类的,正如类是如何创建对象的模板一样;
③元类的实例为类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象;
#创建类的第一种方式 class Foo: def __init__(self,name): self.name=name print(Foo) print(Foo.__dict__) #创建类的第二种方式 def __init__(self,name,age): self.name=name self.age=age def test(self): print('这是test方法') #type需要传三个参数:①类名,②父类(可以有多个父类,所以是个元组)③所创建类的属性和方法 FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test}) print(FFo) print(FFo.__dict__) f=FFo('AA',18) f.test(
①一个类没有声明自己的元类,默认它的元类就是type.除了使用内置元类type,也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类; ②自定义元类可以控制类的产生过程,类的产生过程其实就是元类的调用过程即FFo=Mymeta('FFo',(object,),{...}),调用Mymeta会先产生一个空对象FFo,然后连同调用Mymeta括号内的参数一同传给Mymeta下的__init__方法,完成初始化,如下所示: class Mymeta(type):#只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类 def __init__(self,class_name,class_base,class_dic): # print(class_name)#FFo # print(class_base)#(<class 'object'>,) # ''' # {'__module__': '__main__', '__qualname__': 'FFo', '__doc__': '\n 注释文档\n ', # '__init__': <function FFo.__init__ at 0x000001ADD9106730>} # ''' # print(class_dic) super(Mymeta,self).__init__(class_name,class_base,class_dic)#重用父类功能 if class_name.islower(): raise TypeError('类名%s请修改为驼峰体'%class_name) if '__doc__' not in class_dic or len(class_dic['__doc__'].strip(' \n')) ==0: raise TypeError('类中必须有文档注释,并且文档注释不能为空') class FFo(object,metaclass=Mymeta):#FFo=Mymeta('FFo',(object,),{...}) ''' 注释文档 ''' school='郑大' def __init__(self,name,age): self.name=name self.age=age 元类初始化过程
1.2 Python中类方法,类实例方法,静态方法的区别?
类方法:是类对象的方法,在定义时需要在上方使用"@classmethod"进行装饰,形参为cls.表示类对象,类 对象和实例对象都可调用类方法; 类实例方法:是类实例化对象的方法,只有实例对象可以调用,形参为 self,指代对象本身; 静态方法:是一个任意函数,在其上方使用“@staticmethod”进行装饰,可以用对象直接调用.静态方法实际上跟该类没有太大关系,类和实例对象都可调用静态方法 #拓展 类属性,直接在类中定义的属性,类属性可以通过类对象来修改,无法通过实例对象修改 实例属性,通过实例对象添加的属性,实例属性只能通过实例对象来访问和修改,类对象无法访问修改 class Demo_Property: #类属性 class_name = "Demo_Poperty" def __init__(self,x=0): self.x = x #实例属性 def chng(self,x): #修改实例属性的方法 self.x=x #注意实例属性的引用方式 def chng_cn(self,name): #修改类属性的方法 Demo_Property.class_name = name #注意类属性的引用方式 #属性访问 在类中定义的名字,都是类的属性,细说的话,类有两种属性:数据属性和函数属性(即方法),可以通过__dict__访问属性的 class Student: school='清华大学' def __init__(self,name): self.name = name def choose(self): pass Student.school#访问数据属性,等同于Student.__dict__['school'] Student.choose#访问函数属性,等同于Student.__dict__['choose'] #除了查看属性外,还可以使用Student.attrib=value(修改或新增属性),用del Student.attrib删除属性 #---------------操作对象属性----------------- stu1 = Student('李明') stu1.name #查看,等同于stu1.__dict__['name'] stu1.age=26 #新增,等同于stu1.__dict__['age']=26 stu1.name='AA'#修改等同于stu1.__dict__['name']='AA' del stu1.age #删除,等同于del stu1.__dict__['age']
1.3 Python中如何动态获取和设置类的属性
可以通过反射动态获取和设置对象的属性 if hasattr(Foo,"x"): print(getattr(Foo,'x')) setattr(Foo,'x',6) print(getattr(Foo,'x')) delattr(Foo,'x') print(getattr(Foo,'x'))
二 内存管理与垃圾回收机制
2.1 Python的内存管理机制及调优手段
在定义了变量x=10,会在内存中的栈区开辟一个x的名称空间,同时也会在内存的堆区开辟一个内存空间存放10这个数值,而x = 10相当于把x指向了10的内存地址; 同时把x指向10称为,10被引用了1次; 如果再定义y = 10,同时,y也指向了10的内存地址,加上前面的x,10这个数值同时被x和y引用,也就是被引用了2次; 计算对象被引用的次数,称为引用计数 引用计数是一种非常高效的内存管理手段,当一个Python对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除。 增加引用计数的方式: ①对象被创建,如x=1,此时变量名x指向对象1,对象1的引用计数为1. ②别名被创建,如y=x,此时变量名y也指向对象1,对象1的引用计数为2. ③被作为参数传递给函数,function(x) ④称为容器对象(列表,元组,字段)中的元素 减少引用计数的方式: ①变量名指向另一个对象:x=1;y=x;y=2,本来变量名x,y都指向对象1,引用次数为2,当把对象2赋值给变量名y时,变量名y不再指向对象1,此时引用次数变为1 ②函数结束时,比如function(x)结束后,对象1的引用次数减少1次 ③显示删除别名,如del y ④从容器对象中移除或者容器对象被删除list.remone(x)或del liet
在Python中维护了一个refchain的双向链表,这个链表中存储程序创建的所有对象,每种类型的对象中都有一个ob_refcnt引用计数器的值,最后当引用计数器的值为0时会进行垃圾回收(对象销毁,refchain中移除).
但是在Python中对于那些可以有多个元素组成的对象可能会存在循环引用的问题,为了解决这个问题,Python又引用了标记清除和分代回收,在其内部创建四个链表
①refchain
②2代 (阈值 1次扫描10次)
③1代(阈值 0代扫描10次)
④0代(阈值 0代链表中的元素超过700个)
在源码内部当达到各自的阈值时,就会触发扫描链表进行标记清除的动作(有循环则各自减1)
But,在源码在上述的流程中提出了优化机制,就是缓存.
浙公网安备 33010602011771号