本文概述

Python中的元类是定义类行为方式的类的类。类本身就是元类的实例。 Python中的类定义了该类实例的行为。为了更好地理解元类, 需要具有使用Python类的先验经验。在深入研究元类之前, 让我们先了解一些概念。

Python中的一切都是对象

class TestClass():

pass

my_test_class = TestClass()

print(my_test_class)

可以动态创建Python类

Python中的type使我们能够找到对象的类型。我们可以继续检查上面创建的对象的类型。

type(TestClass)

type

type(type)

type

等等, 发生了什么事?我们希望上面创建的对象的类型为class, 但事实并非如此。坚持那个想法。我们将在后面进一步介绍。我们还注意到类型本身的类型是type。它是类型的实例。该类型所做的另一个神奇的事情是使我们能够动态创建类。让我们在下面展示我们将如何做。如下所示, 将使用类型创建以下所示的srcmini类:

class srcmini():

pass

srcminiClass = type('srcmini', (), {})

print(srcminiClass)

print(srcmini())

在上面的示例中, srcmini是类名, 而srcminiClass是保存类引用的变量。使用type时, 我们可以使用字典传递类的属性, 如下所示:

PythonClass = type('PythonClass', (), {'start_date': 'August 2018', 'instructor': 'John Doe'} )

print(PythonClass.start_date, PythonClass.instructor)

print(PythonClass)

August 2018 John Doe

如果我们希望PythonClass继承自srcmini类, 则在使用type定义类时将其传递给第二个参数

PythonClass = type('PythonClass', (srcmini, ), {'start_date': 'August 2018', 'instructor': 'John Doe'} )

print(PythonClass)

现在, 这两个概念已不复存在, 我们意识到Python使用元类创建了类。我们已经看到Python中的所有东西都是一个对象, 这些对象是由元类创建的。每当我们调用class创建一个class时, 就有一个metaclass可以在后台创建class的魔力。在上面的实践中, 我们已经看到类型可以做到这一点。它类似于创建字符串的str和创建整数的int。在Python中, ___class__attribute使我们能够检查当前实例的类型。让我们在下面创建一个字符串并检查其类型。

article = 'metaclasses'

article.__class__

str

我们也可以使用type(article)检查类型。

type(article)

str

当检查str的类型时, 我们还发现它是类型。

type(str)

type

当我们检查float, int, list, tuple和dict的类型时, 我们将得到类似的输出。这是因为所有这些对象都是type类型。

print(type(list), type(float), type(dict), type(tuple))

我们已经看到类型创建类。因此, 当我们检查__class__的__class__时, 它应该返回类型。

article.__class__.__class__

type

创建自定义元类

在Python中, 我们可以通过在类定义中传递metaclass关键字来自定义类创建过程。这也可以通过继承已在此关键字中传递的类来完成。

class MyMeta(type):

pass

class MyClass(metaclass=MyMeta):

pass

class MySubclass(MyClass):

pass

在下面我们可以看到MyMeta类的类型是type, 而MyClass和MySubClass的类型是MyMeta。

print(type(MyMeta))

print(type(MyClass))

print(type(MySubclass))

当定义一个类并且没有定义元类时, 将使用默认类型的元类。如果给定一个元类, 并且它不是type()的实例, 则它将直接用作元类。

__new__和__init__

也可以通过以下两种方式之一定义元类。我们将在下面解释它们之间的区别。

class MetaOne(type):

def __new__(cls, name, bases, dict):

pass

class MetaTwo(type):

def __init__(self, name, bases, dict):

pass

__new__用于在创建类之前定义字典或基元组的情况。 __new__的返回值通常是cls的实例。 __new__允许不可变类型的子类自定义实例创建。可以在自定义元类中覆盖它以自定义类的创建。通常在创建对象之后调用__init__以便对其进行初始化。

元类__call__方法

根据官方文档, 我们还可以通过在元类中定义一个自定义__call __()方法来覆盖其他类方法, 该方法在调用该类时允许自定义行为。

元类__prepare__方法

根据Python的数据模型文档

一旦标识了适当的元类, 就准备好类名称空间。如果元类具有__prepare__属性, 则将其称为命名空间= metaclass .__ prepare __(名称, 基数, ** kwds)(其中其他关键字参数(如果有)来自类定义)。如果元类没有__prepare__attribute, 则将类名称空间初始化为空的有序映射。 -docs.python.org

使用元类的单例设计

这是一种设计模式, 用于将类的实例化限制为仅一个对象。例如, 当设计一个类以连接到数据库时, 这可能会很有用。一个人可能只想拥有一个连接类实例。

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):

pass

总结

在本文中, 我们了解了什么是元类以及如何在Python编程中实现它们。元类可以应用于日志记录, 创建时注册类以及进行概要分析。它们似乎是非常抽象的概念, 你可能想知道是否需要使用它们。长期使用Pythonista的Tim Peters最好地回答了这个问题。

“元类是比99%的用户应该担心的更深的魔力。如果你想知道是否需要它们, 则不需要(实际上需要它们的人可以肯定地知道他们需要它们, 并且不需要任何解释。为什么)。” -真正的python

如果你想了解有关Python的更多信息, 请启动srcmini的Python编程技能专区。

参考文献

链接一

链接二

python元类使用场景_Python元类使用简介相关推荐

  1. python元类使用场景_python 元类的使用

    class Animal(object): """a class representing an animal""" def __init_ ...

  2. python 元类 详解_Python 元类详解 __new__、__init__、__call__、__metacalss__

    了解元类之前,先了解几个魔术方法: __new__.__init__.__call__ __new__: 对象的创建,是一个静态方法,第一个参数是cls.(想想也是,不可能是self,对象还没创建,哪 ...

  3. python类的应用_Python · 元类(Meta Class)及其应用

    (这里是本章用到的 GitHub 地址)万物皆对象 -- Python 本章所介绍的元类(Meta Class)和之前介绍过的装饰器(Decorator)都是上面这句话的具现,其中装饰器告诉过我们&q ...

  4. python元类的使用_Python 元类使用讲解

    我要一大群的类都具有一种特点,我怎么给他们加上呢?模板嘛,我从这个模板创建一群类不就OK了?那就需要元类了. 定义一个元类(就是一个类的模板!莫多想,还要记住这是类级别的,不是对象级别的!): 代码如 ...

  5. python字典、列表、元祖使用场景_python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍...

    python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍 一丶元祖 1.元祖简介 元祖跟列表类似.只不过是有区别的. 如下: tuple(元祖英文) 跟列表类似, 元素不能 ...

  6. python计算复数的辐角_Python 自定义类中的函数和运算符重载

    如果你曾在字符串(str)对象上进行过 + 或 * 运算,你一定注意到它跟整数或浮点数对象的行为差异: >>> # 加法 >>> 1 + 2 3 >>& ...

  7. python中self做前缀_python 创建类和为什么类方法中self形参必不可少?

    我们观察到在类中定义方法时,都带有self形参,为何必须在方法中定义形参self呢? 因为Python调用方法创建类实例时,将自动传入实参self.每个与类相关联的方法调用都自动传递实参self,他是 ...

  8. python新式类c3算法_Python 新式类继承关系的 C3 算法(Python 2.3 的方法解析顺序,MRO)...

    Python 新式类继承关系的 C3 算法(Python 2.3 的方法解析顺序,MRO) 翻译:刘硕 摘要:本文档面向于想要了解Python 2.3版本中 C3 方法解析顺序的 Python程序开发 ...

  9. python中表示类的公有成员_Python面向对象 | 类的成员

    一. 细分类的组成成员 之前咱们讲过类大致分两块区域,静态字段部分和方法部分. 每个区域详细划分又可以分为: classA: company= '阿里巴巴' #静态变量(静态字段) __tel = ' ...

最新文章

  1. SpringBoot Mybatis解决使用PageHelper一对多分页问题
  2. ITCAST视频-Spring学习笔记(使用JDK中的Proxy技术实现AOP功能)
  3. 修改centos等linux的hostname-永久生效
  4. DP专辑之最长公共子序列及其变形
  5. Openfire3.9.3源代码导入eclipse中开发配置指南(转载)
  6. Codeforces Round #198 (Div. 1) B,C 动态规划
  7. 5动态显示图片_单片机入门 数码管的静态显示和动态显示 壁纸
  8. 最强JAVA核心技术群
  9. 极限分辨率是艾里斑的直径还是半径_小孔成像(二)——衍射,数值孔径和分辨率...
  10. 网络安全实验室CTF—基础关 writeup
  11. java 应用 http spdy_java-删除了ALPN回调:禁用了SPDY和HTTP / 2. alpn-boot是否在引导类路径上?...
  12. 11 Mortal Fibonacci Rabbits
  13. PS学习总结三:修图必备的高阶操作
  14. android 短信接口收拦截,闪修侠科普 | 双11垃圾短信没停过,教你一键屏蔽~
  15. 第二篇:mig IP的创建
  16. 构建单拷贝同源蛋白系统发育树,一条命令提序列!
  17. [bzoj1127][悬线法]KUP
  18. 全国物流企业有哪些 物流企业详细信息怎么查询
  19. tf.repeat(), Tensorflow2.1.0以上
  20. fβ,fα,fT,fmax之间的关系

热门文章

  1. python+selenium之自动生成excle,保存到指定的目录下
  2. Android PullTorefreshScrollview回到顶部
  3. 201452202014520920145309信息安全系统设计基础实验报告(1)
  4. hadoop 学习(1):搭建环境
  5. 调用Android自带日历功能(日历列表单、添加一个日历事件)
  6. Do you want to put on or loose weight?
  7. 冠军奖10万日元+10公斤柠檬!一个简单的柠檬图像分级竞赛
  8. 刚刚,SeetaFace版本升级!新增活体检测等功能
  9. LFFD:轻量级人脸检测器,不止是快
  10. CVPR 2019 | 亮风台发布全球最大单目标跟踪数据集LaSOT