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个参数:

  1. class的名称;
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了元组的单元素写法;
  3. 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__()

工作原理

  1. 紧跟with后面的语句执行后,返回对象中__enter__方法被调用,__enter__方法的返回值会赋给as 后边的变量,
  2. with后面的语句执行完后,会自动调用__exit__方法

关于__exit__详情参考https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/

 

 
 
posted @ 2019-03-27 23:12  种树飞  阅读(791)  评论(0)    收藏  举报