Flask之面向对象补充 metaclass 和with .... as 的用法
创建类的两种方式
方式一
class Foo(object):#这里不指定metaclass时,默认metaclass=type city='北京' def func(self,x): return x+1
方式二
type()函数不仅可以查看数据的类型还可以创建类
Fool=type('Fool',(object,),{"city":"北京",'func':lambda x:x+1},) f=Fool() oo=Fool.func(3) print(f)
要创建一个class对象,type()
函数依次传入3个参数:
- class的名称;
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了元组的单元素写法;
- class的方法名称与函数绑定。
元类
元类就是创建类的类,我们知道在python中一切皆为对象. type也是一个元类,所有的类都直接和间接的是type类的实例对象. 我们又知道object是所有类的父类,同时object又是type类的实例对象,在这里是不是很晕.
在标准库中除了type是元类外,还有ABCMeta等,而Iterable这个类继承了object,同时是ABCMeta的实例对象,然而ABCMteta又继承了type类同时又是type类的实例对象
from collections import Iterable print(Iterable.mro()) print(Iterable.__class__) [<class 'collections.abc.Iterable'>, <class 'object'>] #父类是 <class 'abc.ABCMeta'> #元类是
一个类继承了type类,这个类就是元类
创建类的流程
class Mytype(type): def __init__(self,*args,**kwargs): #1.程序刚启动的时候执行,因为程序启动的时候Foo类就创建了,既然创建了,那么Mytype下的__init__就执行了 print("创建类之前") super(Mytype, self).__init__(*args,**kwargs) print("创建类之后") def __call__(cls, *args, **kwargs): #实例化的时候先执行mytype的call方法,为什么? 因为Foo是由Mytype创建的类也就是对象,加括号后,会执行Mytype类的__call__方法 print("call") obj=cls.__new__(cls,*args,**kwargs) print("__new__") cls.__init__(obj,*args,**kwargs) print("init") return obj class Foo(object,metaclass=Mytype): #当前类是由type类创建,metaclass可以指定当前类是由哪个type创建的 # __metaclsss__=type #python 2的写法 city='北京' def __init__(self,name): self.name=name def __new__(cls, *args, **kwargs): return object.__new__(cls) def func(self,x): return x+1 f=Foo("小红")
执行步骤:
1.执行Mytype的__init__()方法
2.执行Mytype的__call__(),
3.然后执行Foo的__new__方法,
4.最后执行Foo的init方法
metaclass
metaclass用来指定当前类是由哪个类创建的
元类就是用来创建这些类(对象)的类,
函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
如果一个类没有指定metaclass,但是它的父类指定了metaclass,那么这个也是由metaclass指定的类创建的
在wtforms的源码中用到了metaclass的知识,如果想了解就去了解metaclass源码
应用:在wtfroms中第一次看到了metaclass这个属性.
class Form(with_metaclass(FormMeta, BaseForm)):
def with_metaclass(meta, base=object): return meta("NewBase", (base,), {})
其实这里就相当于:
class FormMeta(type): pass class BaseForm: pass class NewBase(BaseForm,metaclass=FormMeta): pass class Form(NewBase): pass #FormMeta继承了type相当于元类
注意:
python原编程大师建议我们在实际生产中,不要定义元类.
面向对象中的with... as...
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
如果一个对象能被with 说明这个对象所对应的类一定有__enter__和__exit__方法,
应用:这个在flask中的离线脚本中用到了.
还有我们的文件操作的时候, with open as f ,当时只记得说用这种方法,就不需要写.f.close() 了,其实我猜里边也是实现了 __enter__ 和__exit__方法.
class Test:
def __enter__(self):
print ("In __enter__()")
return "test_with"
def __exit__(self, type, value, trace):
print("In __exit__()")
def get_example():
print('get_example')
return Test() #调用类Test 生成对象
with get_example() as example:
print ("example:", example)
结果:
get_example
In __enter__()
example: test_with
In __exit__()
工作原理
- 紧跟with后面的语句执行后,返回对象中__enter__方法被调用,__enter__方法的返回值会赋给as 后边的变量,
- with后面的语句执行完后,会自动调用__exit__方法
关于__exit__详情参考https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/