学习python时,对 meta class 并不陌生,django 的model, form定义中经常会遇到class Meta 的代码, 但 django中没有介绍模型与表单中的 meta 属性是怎么回事。 python的众多教程,也很少有作者提到,或把meta class 讲清楚,造成大家以为metaclass 很难理解。 今天我尝试用实例代码的方式,让metaclass 更容易理解与使用。

# django model类可以配置 Meta 类的属性
class Person(models.Model):......class Meta:verbose_name = "人员信息"db_table = "tbl_person"

Python与Java 一样,宣称自己一切皆对象,且有过之而不及。python的数据类型是类对象,甚至函数本身也是对象。 Python object 是所有类型的基类,各种数据类型、函数、class 都是object 的派生类,因此,从object的概念上推理: 存在某些类,可以生成其它类, 这种类就称为meta class., 也称元类

开始之前,我们先看1个经典的问题, 以下的代码的执行结果是什么?

>>> isinstance(type, object)
>>> isinstance(object, type)
>>> isinstance(object, object)
>>> isinstance(type, type)

答案:TrueTrueTrueTrue

在 Python 中,一切皆对象,所以任何对于 object 的实例检查都会返回 Trueisinstance(任何东西, object) #=> True

type 就是一个元类,用于构造所有的 Python 类型。因此所有的类型,无论是 intstr 或是 object,都是 type 类的实例,同时也是对象。

type 还有一个独一无二的特性:它是自身类的实例。

>>> type(5)
<class 'int'>
>>> type(int)
<class 'type'>
>>> type(type)
<class 'type'>

本文将讨论 meta class的定义,以及使用方式。 内容共包含3个主题:

  • 用 type 定义类
  • 如何编写 Metaclass
  • Metaclass 的实际应用

1) Type 来定义类

1个 class 也是1个object, 其包含若干属性,以及一些方法。

type() 方法有两个使用方式
(1) type(x) 返回 x 的类型,
(2) type(cls_name, bases, dict) , 返回1个新类

第(1)种用法就不多说了。 下面使用第(2)种用法来创建一个class对象, 需要传入3个参数:

  • 第1个参数cls_name 是string类型,class的名称;
  • 第2个参数bases 是1个tuple , (object, ) , 指定继承的父类是 object,注意支持多重继承,如果只有一个父类,后面是加个 , 号;
  • 第3个参数是 dictionary 类型, 指定 class的属性与方法名称,这里我们把函数init绑定到方法名__init__上。。

下面演示如何用type创建1个新类。 首先,先用标准的方式,class关键字来创建1个 Food 类。

class Food(object):def __init__(self, food):self.food = fooddef get_food(self):return self.fooddef main():myfood = Food(food='蛋炒饭')print(myfood.get_food())main()

output

蛋炒饭

下面用 type来创建1个Food 类

def init(self, food):self.food = fooddef get_food(self):return self.foodFood = type("Food", (object,),  {'__init__': init,'get_food': get_food,
})myfood = Food(food="蛋炒饭")
print(myfood.get_food())

output:

蛋炒饭

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class

用 type来增加1个子类VegFood, 其父类为Food

def init(self, food):self.food = fooddef get_food(self):return self.foodFood = type("Food", (object,),  {'__init__': init,'get_food': get_food,
})def get_vegfood(self):return {'清炒菠菜', '干煸豆角'}# 新建子类,父类为Food
VegFood = type("VegFood", (Food,), {"get_vegfood": get_vegfood,
})veg = VegFood(food="蛋炒饭")
print(veg.get_food())
print(veg.get_vegfood())

output:

蛋炒饭
{'干煸豆角', '清炒菠菜'}

可以看到,子类 VegFood可以继承 父类Food的方法get_food(),也可以使用子类的方法 get_vegfood()

2) 编写 meta class

metaclass,直译为元类,继承自type. 因此,如前一节的示例, metaclass 也可以用来创建类。

用metaclass来创建类过程:先定义metaclass,就可以创建类,最后创建实例。

所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。

metaclass的定义过程,主要是实现 __new__ 方法,有4个传入参数, 与 type创建类的参数相似

  1. metaclass 自身
  2. 类名
  3. 父类( tuple 类型)
  4. 类的属性与方法字典

metaclass还可以实现1个 __call__方法,在该类被调用时执行此方法。

metacalss 示例 :

class MetaCls(type):"""metaclass的示例"""def __new__(cls, clsname, superclasses, attributedict):print("clsname:", clsname)print("superclasses:", superclasses)print("attrdict:", attributedict)return super(MetaCls, cls).__new__(cls,clsname, superclasses, attributedict)def demo(self):print("Info from demo method")# generate a class, Example
Example = MetaCls('Example', (object, ), {"demo": demo, })
Example.clsname = "ExampleClass"  # 修改 metaclass的属性值
print("class type:", type(Example))
myexample = Example()             # 新建1个Example的实例对象
print(myexample.clsname)          # 打印父类属性值
myexample.demo()                  # 打印子类方法

output

clsname: Example
superclasses: (<class 'object'>,)
attrdict: {'demo': <function demo at 0x00000169DF2CC280>}
class type: <class '__main__.MetaCls'>
ExampleClass
Info from demo method

从上例 可以看到, Example类的生成方式,就是 MetaCls类的实例 化过程,example可以添加自己的方法,可以修改从父类继承的属性。

3) metaclass应用

实际开发中遇到的metaclass是django中定义model, form时,可以定义metaclass的属性,其实就是django的ORM使用了 metaclass的编程方式,由于其实现较复杂,就不深入讨论。

这里我们来看1个更简单,而且非常实用的metaclass的例子: 用metaclass实现单例模式

单例模式提供了这样一个机制,即确保类有且只有一个特定类型的对象,并提供全局 访问点。因此,单例模式通常用于下列情形,例如日志记录或数据库操作、打印机后台处 理程序,以及其他程序—该程序运行过程中只能生成一个实例,以避免对同一资源产生 相互冲突的请求。

class SingletonMeta(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)return cls._instances[cls]class SingletonClass(metaclass=SingletonMeta):_name = ''_age = 20def greet(self, name):self._name = nameprint("hello ",self._name)def set_age(self,age):self._age=agedef get_age(self):return self._ages = SingletonClass()
print("Object created", s)
s.greet("Jack")
s.set_age(25)
s1 = SingletonClass()
print("Object created", s1)
s1.greet("Peter")
print(s1.get_age())

output :

Object created <__main__.SingletonClass object at 0x000001685344DC40>
hello  Jack
Object created <__main__.SingletonClass object at 0x000001685344DC40>
hello  Peter
25

可以看到,SingletonMeta用metaclass的方法定义了1个单例类, SingletonClass继承自SingletonMeta, s 与 s1 虽然分别实例化,但内存中的地址都指向同1个SingletonClass对象,实现了单例化。
而且metaclass实现单例模式,比 object方式实现的单例化有明显的优势,任何类都可以通过继承SingletonMeta实现单例模式, 是不是很酷.

----- 如有疑问,欢迎讨论------

深入浅出讲解 Python 元类(Metaclass)的使用相关推荐

  1. python元类_python中的元类 metaclass

    python中的元类 metaclass 在python中,类(class)本身也是一个实例对象, 它的类型则是元类, 如果没有指明, 则自定义类的类型是type. 换言之, 我们所定义的普通类都是t ...

  2. Python元类(type()和metaclass)

    1. 元类是什么 众所周知,对象由类实例化而来,类是对象的模板,而python一切皆对象,类也是对象,它由元类(type)创建,所以元类是类的类,是类的模板 2. 创建类的另一种方法 一般情况下,我们 ...

  3. python中的元类_Python中的元类(metaclass)

    提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自身有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理 ...

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

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

  5. python中的元类Metaclass

    python中的元类Metaclass 理解元类之前需要学习的知识 如果说让我们创建一个类,最先想到的肯定是用class创建,当我们使用class创建类的时候,python解释器自动创建这个对象,但是 ...

  6. 元类(metaclass)

    目录 一.引言 二.什么是元类 三.为什么用元类 四.内置函数exec(储备) 五.class创建类 5.1 type实现 六.自定义元类控制类的创建 6.1 应用 七.__call__(储备) 八. ...

  7. python 元类工厂模式_Python进阶丨如何创建你的第一个Python元类?

    摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...

  8. 如何创建你的第一个Python元类?

    Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一.通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类.本文介绍 ...

  9. python3元类_3.python元类编程

    1.1.propety动态属性 在面向对象编程中,我们一般把名词性的东西映射成属性,动词性的东西映射成方法.在python中他们对应的分别是属性self.xxx和类方法.但有时我们需要的属性需要根据其 ...

最新文章

  1. Linux内核裁剪及编译
  2. Kindle:自动追更之云上之旅
  3. oracle创建dblink语句_一文看懂Oracle12c中多租户(容器)从种子创建PDB
  4. 单机运行环境搭建之 --CentOS-6.4安装MySQL 5.6.10并修改MySQL的root用户密码
  5. HTML5实现Word中文字全环绕图片效果
  6. 滑动窗口1——无重复字符的最长字串
  7. php 用什么缓存最好,在PHP中缓存中/大型数据集的一些最好的工具/策略是什么?...
  8. iOS 点击tabbarItem的时候根据登录状态判断加载哪个视图控制器
  9. CSS:淘宝商品展示样式
  10. 图像处理——matlab人脸识别(1)
  11. 微信小程序云开发教程-墨刀原型工具入门
  12. STM32单片机学习教程
  13. 如何查看电脑系统版本
  14. 无人货架上演生死时速,谁会成为最后的赢家?
  15. GT9xx触摸屏驱动总结
  16. Windows10 1903 应用商店错误 代码: 0x80131500 解决办法
  17. Tensorflow选择CPU或GPU运行
  18. 视频教程-Cesium入门-JavaScript
  19. 新浪微博瘫痪近一小时无法登陆,现已恢复
  20. oracle decode函数什么意思,oracle decode函数的用法

热门文章

  1. 001 | “版绘童印”——疫情时代下版画在儿童插画中应用研究 | 大学生创新训练项目申请书 | 极致技术工厂
  2. 高通揭秘“地表最强”骁龙855,专为AI新增张量加速器,每秒7万亿次运算
  3. windows无法自动修复此计算机 鼠标,win10出现你的账户已被停用。开机按F8进不去。自动修复鼠标和键盘都用...
  4. jboot-admin学习
  5. 33岁跳槽无路,走投无路之际受贵人指点,成功上岸阿里(Java岗)
  6. 对于STM32的ADC芯片的思考
  7. 谈谈Python的编译和反编译
  8. 【工具篇】Unity运行期间日志查看的两种方式
  9. 如何注册成为腾讯QQ互联个人开发者
  10. 让人又爱又恨的C语言!