荆州热线,神剑永恒无弹窗,梦醒三国
在面向对象的程序设计中类和对象是其重要角色,我们知道对象是由类实例化而来,那么类又是怎么生成的呢?答案是通过元类。本篇文章将介绍元类相关知识,并剖析元类生成类的过程,以及元类的使用等内容,希望能帮助到正在学习python的同仁。
在python中有这样一句话“一切皆对象”,没错你所知道的dict、class、int、func等等都是对象,让我们来看以下一段代码来进行说明:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:wd class foo(object): pass def func(): print('func') print(foo.__class__) print(func.__class__) print(int.__class__) print(func.__class__.__class__) 结果: <class 'type'> <class 'function'> <class 'type'> <class 'type'>
说明:__class__方法用于查看当前对象由哪个类生成的,正如结果所见其中foo和int这些类(对象)都是由type创建,而函数则是由function类创建,而function类则也是由type创建,究其根本所有的这些类对象都是由type创建。这里的type就是python内置的元类,接下来谈谈type。
上面我们谈到了所有的类(对象)都是由type生成,那么不妨我们看看type定义,以下是python3.6中内置type定义部分摘抄:
class type(object): """ type(object_or_name, bases, dict) type(object) -> the object's type type(name, bases, dict) -> a new type """ def mro(self): # real signature unknown; restored from __doc__ """ mro() -> list return a type's method resolution order """ return []
type(类名,该类所继承的父类元祖,该类对应的属性字典(k,v))
利用该语法我们来穿件一个类(对象)foo:
foo=type('foo',(object,),{'name':'wd'}) print(foo) print(foo.name) 结果: <class '__main__.foo'> wd
当然也可以实例化这个类(对象):
foo=type('foo',(object,),{'name':'wd'}) obj=foo() print(obj.name) print(obj) print(obj.__class__) 结果: wd <__main__.foo object at 0x104482438> <class '__main__.foo'>
这样创建方式等价于:
class foo(object): name='wd'
其实上面的过程也就是我们使用class定义类生成的过程,而type就是python中的元类。
经过以上的介绍,说白了元类就是创建类的类,有点拗口,姑且把这里称为可以创建类对象的类。列如type就是元类的一种,其他的元类都是通过继承type或使用type生成的。通过元类我们可以控制一个类创建的过程,以及包括自己定制一些功能。 例如,下面动态的为类添加方法:
def get_name(self): print(self.name) class mytype(type): def __new__(cls, cls_name, bases, dict_attr): dict_attr['get_name'] = get_name #将get_name 作为属性添加到类属性中 return super(mytype, cls).__new__(cls, cls_name, bases, dict_attr) class foo(metaclass=mytype): def __init__(self, name): self.name = name obj = foo('wd') obj.get_name()#调用该方法 结果: wd
了解类元类的作用,我们知道其主要目的就是为了当创建类时能够根据需求改变类,在以上的列子中我们介绍了使用方法,其中就像中关于对元类的使用建议一样,绝大多数的应用程序都非必需使用元类,并且使用它可能会对你的代码带来一定的复杂性,但是就元类的使用而言其实很简单,其场景在于:
1.对创建的类进行校验(拦截);
2.修改类;
3.为该类定制功能;
使用元类是时候经典类和新式类时候有些不同,新式类通过参数metaclass,经典类通过__metaclass__属性:
class foo(metaclass=mytype): #新式类 pass class bar: # 经典类 __metaclass__ = mytype pass
在解释元类的时候有提到过,元类可以是type,也可以是继承type的类,当然还可以是函数,只要它是可调用的。但是有个必要的前提是该函数使用的是具有type功能的函数,否则生成的对象可能就不是你想要的(在后续的原理在进行讲解)。以下示例将给出使用函数作为元类来创建类:
def class_creater(cls_name, bases, dict_attr): return type(cls_name, bases, dict_attr) class foo(metaclass=class_creater): def __init__(self,name): self.name=name obj=foo('wd') print(obj.name) #wd
class foo(object): def __init__(self, name): print('this is __init__') self.name = name def __new__(cls, *args, **kwargs): print('this is __new__') return object.__new__(cls) def __call__(self, *args, **kwargs): print("this is __call__") obj=foo('wd') # 实例化 obj() # 触发__call__ 结果: this is __new__ this is __init__ this is __call__
有了这个知识,再来看看使用元类生成类,以下代码定义来一个元类继承来type,我们重写__new__和__init__方法(其实什么也没干),为了说明类的生成过程:
class mytype(type): def __init__(self, cls_name, bases, cls_attr): print("mytype __init__", cls_name, bases) def __new__(cls, cls_name, bases, cls_attr): print("mytype __new__", cls_name, bases) return super(mytype, cls).__new__(cls, cls_name, bases, cls_attr) class foo(metaclass=mytype): def __init__(self, name): print('this is __init__') self.name = name def __new__(cls, *args, **kwargs): print('this is __new__') return object.__new__(cls) print("line -------") obj = foo('wd') # 实例化 结果: mytype __new__ foo () mytype __init__ foo () line ------- this is __new__ this is __init__
解释说明:
class mytype(type): def __init__(self, cls_name, bases, cls_attr): print("mytype __init__", cls_name, bases) def __new__(cls, cls_name, bases, cls_attr): print("mytype __new__", cls_name, bases) return super(mytype, cls).__new__(cls, cls_name, bases, cls_attr) def __call__(self, *args, **kwargs): print('mytype __call__') class foo(metaclass=mytype): def __init__(self, name): print('this is __init__') self.name = name def __new__(cls, *args, **kwargs): print('this is __new__') return object.__new__(cls) def __call__(self, *args, **kwargs): print("this is __call__") print("before -------") obj = foo('wd') # 实例化 print("after -------") print(obj) 结果: mytype __new__ foo () mytype __init__ foo () before ------- mytype __call__ after ------- none
你会发现,当foo实例化时候执行了元类的__call__,你从python的一切皆对象的方式来看,一切都是顺理成章的,因为这里的foo其实是元类的对象,对象+()执行元类的__call__方法。请注意,在foo进行实例化时候返回的对象是none,这是因为__call__方法返回的就是none,所以在没有必要的前提下最好不要随意重写元类的__call__方法,这会影响到类的实例化。__call__方法在元类中作用是控制类生成时的调用过程。
通过__call__方法我们能得出结果就是__call__方法返回什么,我们最后得到的实例就是什么。还是刚才栗子,我们让foo实例化以后变成一个字符串:
class mytype(type): def __init__(self, cls_name, bases, cls_attr): print("mytype __init__", cls_name, bases) def __new__(cls, cls_name, bases, cls_attr): return super(mytype, cls).__new__(cls, cls_name, bases, cls_attr) def __call__(self, *args, **kwargs): return 'this is wd' class foo(metaclass=mytype): def __init__(self, name): print('this is __init__') self.name = name def __new__(cls, *args, **kwargs): print('this is __new__') return object.__new__(cls) def __call__(self, *args, **kwargs): print("this is __call__") obj = foo('wd') # 实例化 print(type(obj),obj) 结果: mytype __init__ foo () <class 'str'> this is wd
既然__call__方法返回什么,我们实例化生成的对象就是什么,那么在正常的流程是返回的是foo的对象,而foo的对象是由foo的__new__和foo的__init__生成的,所以在__call__方法的内部又有先后调用了foo类的__new__方法和__init__方法,如果我们重写元类的__call__方法,则应该调用对象的__new__和__init__,如下:
class mytype(type): def __init__(self, cls_name, bases, cls_attr): print("mytype __init__", cls_name, bases) def __new__(cls, cls_name, bases, cls_attr): return super(mytype, cls).__new__(cls, cls_name, bases, cls_attr) def __call__(self, *args, **kwargs): print("mytype __call__", ) obj = self.__new__(self) print(self, obj) self.__init__(obj, *args, **kwargs) return obj class foo(metaclass=mytype): def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls) obj = foo('wd') # 实例化 print(obj.name) 结果: mytype __init__ foo () mytype __call__ <class '__main__.foo'> <__main__.foo object at 0x1100c9dd8> wd
同样,当函数作为元类时候,metaclass关键字会调用其对应的函数生成类,如果这个函数返回的不是类,而是其他的对象,那么使用该函数定义的类就得到的就是该对象,这也就是为什么我说使用函数作为元类时候,需要有type功能,一个简单的示例:
def func(cls_name, bases, dict_attr): return 'this is wd' class foo(metaclass=func): def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls) print(foo, "|", type(foo)) # 结果:this is wd | <class 'str'> obj=foo('wd') #报错
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Python爬虫:Request Payload和Form Data的简单区别说明
浅谈Python中threading join和setDaemon用法及区别说明
Python3-异步进程回调函数(callback())介绍
python继承threading.Thread实现有返回值的子类实例
Python中使用threading.Event协调线程的运行详解
网友评论