metaclass
创建类的两种方式
方式一
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 __new__(cls, name, bases, attrs): # 1.实例化Mytype()创建Foo类时首先会调用Mytype下的__new__方法,会获取到 Foo下的所有属性比如 city=北京 print(f"执行Mytype的__new__方法cls是{cls.__name__}类") xx = super().__new__(cls, name, bases, attrs) return xx def __init__(self, *args, **kwargs): # 2.初始化Mytype类时调用了Mytype下的__init__方法 print(f"执行Mytype的__init__前") super(Mytype, self).__init__(*args, **kwargs) print("执行Mytype的__init__后") def __call__(cls, *args, **kwargs): # 3.Foo()时先执行mytype的__call__方法,在该方法里会分别调用 Foo自己的__new__和__init__ print(f"执行Mytype的__call__cls是{cls.__name__}类") obj = cls.__new__(cls, *args, **kwargs) cls.__init__(obj, *args, **kwargs) return obj class Foo(object, metaclass=Mytype): # metaclass可以指定当前类是由哪个元类创建的 city = '北京' def __new__(cls, *args, **kwargs): # 4. 先调用__new__方法 print(f'执行Foo__new__,cls是{cls.__name__}类') return object.__new__(cls) def __init__(self, name): # 5.调用__init___方法 print('执行Foo__init__') self.name = name def func(self, x): return x + 1 f = Foo("小红")
执行结果:
执行Mytype的__new__方法cls是Mytype类
执行Mytype的__init__前
执行Mytype的__init__后
执行Mytype的__call__cls是Foo类
执行Foo__new__,cls是Foo类
执行Foo__init__
metaclass
metaclass用来指定当前类是由哪个元类创建的
元类就是用来创建这些类(对象)的类,
函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
如果一个类没有指定metaclass,但是它的父类指定了metaclass,那么这个也是由metaclass指定的类创建的
应用:
1. 在 drf中的序列化源码中看到该属性
2 .在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 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
上下文管理器:即含有__enter__和__exit__方法的对象就是上下文管理器
如果一个对象能被with 说明这个对象所对应的类一定有__enter__和__exit__方法。
with后边as之前的代码部分就是上下文管理器,as后的就是上下文管理器中__enter__方法返回的东西
应用:这个在flask中的离线脚本中用到了.我们随便写一个py文件在py文件中,使用curren_app,我们会出现flask的经典错误,不在上下文之内。
from flask import Flask,current_app app = (__name__) print(current_app.config['DEBUG'])
RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that needed to interface with the current application object in some way. To solve this, set up an application context with app.app_context(). See the documentation for more information.
出现这个原因就是,current_app会从栈中调用Appcontext,然而此时我们并没有操作请求,APPcontext也就没有压入栈中。即current_app也就不在栈中。
解决方法:使用上下文管理器
from flask import Flask,current_app app = Flask(__name__) with app.app_context(): #实现了一个上下文管理器 print(current_app.config['DEBUG'])
看一下源码:

还有我们的文件操作的时候, 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/
浙公网安备 33010602011771号