笔记-python-元类metaclass

1.      元类

1.1.    类也是对象

class Person(object):

pass

上面的代码会在内存中创建一个类,它也是对象,

  1. 可以将它赋值给一个变量;
  2. 可以拷贝它;
  3. 可以为它增加属性;
  4. 可以将它作为函数参数进行传递;

1.2.    动态地创建类

类也是对象,可以在运行时动态的创建它们,可以在函数中创建类。

>>> def chosse_class(name):

if name == 'fa':

class Fa(object):

pass

return Fa

else:

class Fb(object):

pass

return Fb

>>> myclass = chosse_class('ff')

>>> dir(myclass)

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

>>> myclass

<class '__main__.chosse_class.<locals>.Fb'>

>>> myclass()

<__main__.chosse_class.<locals>.Fb object at 0x00000092615AFD30>

使用class可以创建类,是通过python内置功能函数完成的,能不能手动创建类呢?

1.3.    type

type(1)  #<class 'int'>

常用来查看类型,但type还可以动态的创建类。

类的三大关键组成部分:类名,类的基类(们),类的名称空间;将这些参数传递给type就可以手动创建类了。

语法:

type(类名, 父类元组(继承,可以为空),属性字典)

下面两部分代码的功能是一样的;

>>> class Pa(object):

pass

>>> Pa

<class '__main__.Pa'>

>>> myclass = type('Pb', (), {})

>>> myclass

<class '__main__.Pb'>

1.4.    元类

元类就是类的类,是道生一的道;

简单来说,要创建实例需要先定义类;要定义类需要先创建类,创建类的根据是metaclass。

换句话说就是得先定义metaclass,再创建类,最后创建实例。

type是一个元类,type是python创建所有类的元类,类是type实例化的结果。

可以通过查看__class__属性来检查。

>>> age = 35

>>> age.__class__

<class 'int'>

>>> age.__class__.__class__

<class 'type'>

>>> foo.__class__

<class 'function'>

>>> foo.__class__.__class__

<class 'type'>

说明:

  1. __class__表示实例的类;
  2. __bases__表示父类;

总而言之,type是python的默认的元类,所有的类都是从它而来。

使用type创建类,实际上是:

Student = type()返回的一个类对象

student = Student()

2.      自定义元类

有时需要自定义元类。

定义语法:

class Foo(base1,base2,metaclass = mymeta):

也可以在类基列表中使用* args和** kwargs -style参数:

class Foo(base1, base2, metaclass=mymeta, private=True):

2.1.    元类原理及自定义元类实现

官方文档PEP3115太坑了,下面的代码很好的解释了元类原理。

引用自https://www.cnblogs.com/ManyQian/p/8882639.html

2.1.1.   步骤一

# 控制类的创建

class Mymeta(type):  # 继承默认元类的一堆属性

def __init__(self, class_name, class_bases, class_dic):

if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():

raise TypeError('必须为类指定文档注释')

if not class_name.istitle():

raise TypeError('类名首字母必须大写')

super(Mymeta, self).__init__(class_name, class_bases, class_dic)

class People(object, metaclass=Mymeta):

country = 'China'

def __init__(self, name, age):

self.name = name

self.age = age

def talk(self):

print('%s is talking' % self.name)

解释:People类具备了Mymeta中的校验功能。

2.1.2.   步骤二

# 控制类实例化的行为。

class People(object,metaclass=type):

def __init__(self,name,age):

self.name=name

self.age=age

def __call__(self, *args, **kwargs):

print(self,args,kwargs)

obj=People('duoduo',18)

# 对象obj是可以调用的,具体参考__call__()

obj(1,2,3,a=1,b=2,c=3)

#输出:<__main__.People object at 0x0000005BBD68E4E0> (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}

#总结:如果说类People是元类type的实例,那么在元类type内肯定也有一个__call__,会在调用People('duoduo',18)时触发执行,然后返回一个初始化好了的对象obj

2.1.3.   步骤三

# 自定义元类,控制类的调用(即实例化)的过程

class Mymeta(type): #继承默认元类的一堆属性

def __init__(self,class_name,class_bases,class_dic):

if not class_name.istitle():

raise TypeError('类名首字母必须大写')

super(Mymeta,self).__init__(class_name,class_bases,class_dic)

def __call__(self, *args, **kwargs):

#self=People

print(self,args,kwargs) #<class '__main__.People'> ('egon', 18) {}

#1、实例化People,产生空对象obj

obj=object.__new__(self)

#2、调用People下的函数__init__,初始化obj

self.__init__(obj,*args,**kwargs)

#3、返回初始化好了的obj

return obj

class People(object,metaclass=Mymeta):

country='China'

def __init__(self,name,age):

self.name=name

self.age=age

def talk(self):

print('%s is talking' %self.name)

obj=People('duoduo',18)

print(obj.__dict__) #{'name': 'duoduo', 'age': 18}

理解:

从上面的代码我们可以看出,对象的产生其实就是,调用了类,进而触发了元类的__call__ 方法,

但是调用类产生的是对象,说明元类的__call__ 方法是用来产生对象的。

说明元类的__call__ 方法就做了下面的几件事

1、创造了一个空对象

2、调用了类的__init__ 方法

3、将参入传入__init__方法中

2.1.4.   步骤四

class Mymeta(type):

def __init__(self,class_name,class_bases,class_dic):

if not class_name.istitle():

raise TypeError('类名首字母必须大写')

super(Mymeta,self).__init__(class_name,class_bases,class_dic)

def __call__(self, *args, **kwargs):

#self=People

print(self,args,kwargs) #<class '__main__.People'> ('egon', 18) {}

#1、调用self,即People下的函数__new__,在该函数内完成:1、产生空对象obj 2、初始化 3、返回obj

obj=self.__new__(self,*args,**kwargs)

#2、一定记得返回obj,因为实例化People(...)取得就是__call__的返回值

return obj

class People(object,metaclass=Mymeta):

country='China'

def __init__(self,name,age):

self.name=name

self.age=age

def talk(self):

print('%s is talking' %self.name)

def __new__(cls, *args, **kwargs):

obj=object.__new__(cls)

cls.__init__(obj,*args,**kwargs)

return obj

obj=People('duoduo',18)

print(obj.__dict__) #{'name': 'duoduo', 'age': 18}

2.1.5.   步骤五:案例,元类实现单例模式

#步骤五:基于元类实现单例模式

# singleton metaclass

class Singleton(type):

print('www')

def __call__(cls, *args, **kwargs):

if not hasattr(cls, '_instance'):

print(cls)

cls._instance = super(Singleton, cls).__call__(*args, **kwargs)

return cls._instance

class MyClass(metaclass=Singleton):

a = 4

a1 = MyClass()

a2 = MyClass()

print(a1 == a2) #True

附录

3.      type和object,class的关系

上面的内容中没有提到type和object的关系,这中间也有点绕。

先说结果,在Python的世界中,object是父子关系的顶端,所有的数据类型的父类都是它;type是类型实例关系的顶端,所有对象都是它的实例。

object是type实例化的结果,总之,一个类/函数调用后返回了一个类,这个类/函数就是元类了。如果你愿意,原理上是可以返回一个和元类相同的类的,type就是这样干的。

type(type) # <class 'type'>

更详细的信息如下:

print(type.__class__,type.__bases__)

print(object.__class__, object.__bases__)

输出:

<class 'type'> (<class 'object'>,)

<class 'type'> ()

其它内置继承于object:

>>> list.__class__

<class 'type'>

>>> list.__bases__

(<class 'object'>,)

>>> int.__class__

<class 'type'>

>>> int.__bases__

(<class 'object'>,)

比较奇特的是None,None是Python的特殊类型,NoneType对象,它只有一个值None. 但NoneType是未定义的,也没有父类。

它不支持任何运算也没有任何内建方法。

None和任何其他的数据类型比较永远返回False。

None有自己的数据类型NoneType。

你可以将None复制给任何变量,但是你不能创建其他NoneType对象。

>>>type(None)

<class 'NoneType'>

>>> None.__bases__

Traceback (most recent call last):

File "<pyshell#53>", line 1, in <module>

None.__bases__

AttributeError: 'NoneType' object has no attribute '__bases__'

>>> dir(NoneType)

Traceback (most recent call last):

File "<pyshell#51>", line 1, in <module>

dir(NoneType)

NameError: name 'NoneType' is not defined

3.1.    type,object关系图

笔记-python-元类metaclass的更多相关文章

  1. python 元类metaclass

    文章转自:http://www.cnblogs.com/linhaifeng/articles/8029564.html 一 知识储备 exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域 ...

  2. Python元类(metaclass)以及元类实现单例模式

    这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...

  3. python 元类 MetaClass

    type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: class Hel ...

  4. python 元类——metaclass

    from stack overflow:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python Classes ...

  5. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  6. 深刻理解Python中的元类metaclass(转)

    本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...

  7. 深刻理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  8. [转] 深刻理解Python中的元类(metaclass)

    非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...

  9. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  10. 深刻理解Python中的元类(metaclass)【转】

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

随机推荐

  1. AWS ELB Sticky Session有问题?别忘了AWSELB cookie

    我们的产品中有两个Module,分别部署在独立的Linux机器上,Module 1需要向Module 2发起Http请求来获得服务.由于Module 2有多台,因此我们会在Module 2前部署一台负 ...

  2. 笨办法学Python(十九)

    习题 19: 函数和变量 函数这个概念也许承载了太多的信息量,不过别担心.只要坚持做这些练习,对照上个练习中的检查点检查一遍这次的联系,你最终会明白这些内容的. 有一个你可能没有注意到的细节,我们现在 ...

  3. ubuntu terminal copy paste

    copy: ctrl + insert paste: shift + insert

  4. Python 看书的一些记录 运算符重载

    1.类和模块有什么关系? (1)类是模块的一部分,是模块对象的属性. (2)类和模块都是命名空间,但是类是对于语法的.模块是对于文件的 (3)类支持多个实例,但是模块被导入时只有一个. 2.什么是抽象 ...

  5. ie6下按钮下边框消失不显示的问题

    最近网站做改版,又发现一个ie6奇葩的问题,就一个很普通带边框的按钮,但在ie6中下边框不显示,ie7没有测试不知道是不是也不显示,其他浏览器正常 代码和预览效果如下: <style> b ...

  6. MVC中某个页面不需要引用母版页的正确写法

    有些页面想使用单独的样式不想用母版页的时候,可以在开始声明下,就可以不用母版页的CSS和JS引用了语法如下: @{Layout = "";} . 非常之简单

  7. 5、Oracle备份(oracle备份脚本配置)

    1.1 Oracle数据库备份 1.1.1 链接Oracle介质管理库 请在数据库节点上操作. [oracle@db01/usr/openv/netbackup/bin]$ ./oracle_link ...

  8. P1909 买铅笔

    题目描述 P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物.她发现商店一共有 33种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同.为了公平起 见,P老师决定只买同一种包装的铅笔 ...

  9. chrome 浏览器插件开发(二)—— 通信 获取页面变量 编写chrome插件专用的库

    在chrome插件的开发过程中,我遇到了一些问题,在网上找了不少文章,可能是浏览器升级的原因,有一些是有效的也有无效的.下面我简单的分享一下我遇到的坑,以及我把这些坑的解决方案整理而成的js库 —— ...

  10. jeDate日期控件

    http://www.jayui.com/jedate/     这是日期控件官网,可以去里面下载使用 前台 <%@ Page Language="C#" AutoEvent ...