笔记-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. Miner3D 数据分析软件

    现在,越来越多的专业人士愿意选择Miner3D来帮助他们进行快速高效的智能决策,因为它是一个功能强大.专业性强.海量数据存储能力.三维可视化效果逼真的数据分析解决工具.Miner3D凭借出色的图形质量 ...

  2. Android 编码风格规范,很赞哦

    1. 前言 这份文档参考了 Google Java 编程风格规范和 Google 官方 Android 编码风格规范.该文档仅供参考,只要形成一个统一的风格,见量知其意就可. 1.1 术语说明 在本文 ...

  3. centos7.4 系统安装指导

    centos7 系统安装指导 安装前规划 下载安装文件 安装过程设置 安装后系统基本设置 安装前规划 CentOS 7.x系列只有64位系统,没有32位. 生产服务器建议安装CentOS-7-x86_ ...

  4. Azure 本月最新活动,速度Mark!

    很多时候,为了知晓 Azure 相关活动的信息,需要到处查阅.问朋友同事,这样既麻烦又易造成延误.为方便广大粉丝,我们推出每月活动合集,帮您第一时间了解 Azure 最新活动,还等什么,一起来看吧! ...

  5. JavaScript 闭包的详细分享(三种创建方式)(附小实例)

    JavaScript闭包的详细理解 一.原理:闭包函数--指有权访问私有函数里面的变量和对象还有方法等:通俗的讲就是突破私有函数的作用域,让函数外面能够使用函数里面的变量及方法. 1.第一种创建方式 ...

  6. JavaScript Date对象方法详细总结

    Date 对象方法 方法 描述 Date() 返回当日的日期和时间. getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31). getDay() 从 Date 对象返回一周中的某 ...

  7. MYSQL导入excel

    MYSQL使用navicat导入excel 第一步:首先需要准备好有数据的excel 第二步:选择"文件"->"另存为",保存为"CSV(逗号分 ...

  8. CRM, C4C和Hybris的工作流简介

    CRM的例子 Step by Step to debug IC inbox workflow WS14000164 C4C Custom recipient determination in work ...

  9. cesium 显示视角高度以及鼠标经纬度

    HTML中的内容 <div id="cesiumContainer"> <!-- 设置经纬度显示 --> <span style="font ...

  10. IOS 拉伸图片(封装)

    /** * 根据图片名返回一张能够自由拉伸的图片 */ +(UIImage *)resizedImage:(NSString *)name { UIImage *image=[UIImage imag ...