Python——元类

2023-11-12

作者:小明
链接:https://zhuanlan.zhihu.com/p/30861351
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

什么是元类?

 

理解元类(metaclass)之前,我们先了解下Python中的OOP和类(Class)。

面向对象全称 Object Oriented Programming 简称OOP,这种编程思想被大家所熟知。它是把对象作为一个程序的基本单元,把数据和功能封装在里面,能够实现很好的复用性,灵活性和扩展性。OOP中有2个基本概念:类和对象:

1. 类是描述如何创建一个对象的代码段,用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法

2. 对象是类的实例(Instance)。

我们举个例子:

In : class ObjectCreator(object):
...:     pass
...:

In : my_object = ObjectCreator()

In : my_object

而Python中的类并不是仅限于此:

In : print(ObjectCreator)
<class '__main__.ObjectCreator'>

ObjectCreator竟然可以被print,所以它的类也是对象!既然类是对象,你就能动态地创建它们,就像创建任何对象那样。我在日常工作里面就会有这种动态创建类的需求,比如在mock数据的时候,现在有个函数func接收一个参数:

In : def func(instance):
...:     print(instance.a, instance.b)
...:     print(instance.method_a(10))
...:

正常使用起来传入的instance是符合需求的(有a、b属性和method_a方法),但是当我想单独调试func的时候,需要「造」一个,假如不用元类,应该是这样写:

In : def generate_cls(a, b):
...:     class Fake(object):
...:         def method_a(self, n):
...:             return n
...:     Fake.a = a
...:     Fake.b = b
...:     return Fake
...:

In : ins = generate_cls(1, 2)()

In : ins.a, ins.b, ins.method_a(10)
Out: (1, 2, 10)

你会发现这不算是「动态创建」的:

1. 类名(Fake)不方便改变

2. 要创建的类需要的属性和方法越多,就要对应的加码,不灵活。

我平时怎么做呢:

In : def method_a(self, n):
...:     return n
...: 
In : ins = type('Fake', (), {'a': 1, 'b': 2, 'method_a': method_a})()

In : ins.a, ins.b, ins.method_a(10)
Out: (1, 2, 10)

到了这里,引出了type函数。本来它用来能让你了解一个对象的类型:

In : type(1)
Out: int

In : type('1')
Out: str

In : type(ObjectCreator)
Out: type

In : type(ObjectCreator())
Out: __main__.ObjectCreator

另外,type如上所说还可以动态地创建类:type可以把对于类的描述作为参数,并返回一个类。

用来创建类的东东就是「元类」,放张图吧:

MyClass = type('MyClass', (), {})

这种用法就是由于type实际上是一个元类,作为元类的type在Python中被用于在后台创建所有的类。在Python语言上有个说法「Everything is an object」。包整数、字符串、函数和类... 所有这些都是对象。所有这些都是由一个类创建的:

In : age = 35
In : age.__class__
Out: int

In : name = 'bob'
In : name.__class__
Out: str
...

现在,任何__class__中的特定__class__是什么?

In : age.__class__.__class__
Out: type

In : name.__class__.__class__
Out: type
...

如果你愿意,你可以把type称为「类工厂」。type是Python中内建元类,当然,你也可以创建你自己的元类。

创建自己的元类

Python2创建类的时候,可以添加一个__metaclass__属性:

class Foo(object):
    __metaclass__ = something...
    [...]

如果你这样做,Python会使用元类来创建Foo这个类。Python会在类定义中寻找__metaclass__。如果找到它,Python会用它来创建对象类Foo。如果没有找到它,Python将使用type来创建这个类。

在Python3中语法改变了一下:

class Simple1(object, metaclass=something...):
    [...]

本质上是一样的。拿一个4年前写分享的元类例子(就是为了推荐你来阅读 ?[我的PPT:《Python高级编程》](dongweiming/Expert-Python) )吧:

class HelloMeta(type):
    def __new__(cls, name, bases, attrs):
        def __init__(cls, func):
            cls.func = func
        def hello(cls):
            print 'hello world'
        t = type.__new__(cls, name, bases, attrs)
        t.__init__ = __init__
        t.hello = hello
        return t
        
class New_Hello(object):
    __metaclass__ = HelloMeta

New_Hello初始化需要添加一个参数,并包含一个叫做hello的方法:

In : h = New_Hello(lambda x: x)

In : h.func(10), h.hello()
hello world
Out: (10, None)

PS: 这个例子只能运行于Python2。

在Python里__new__方法创建实例,__init__负责初始化一个实例。对于type也是一样的效果,只不过针对的是「类」,在上面的HelloMeta中只使用了__new__创建类,我们再感受一个使用__init__的元类:

In : class HelloMeta2(type):
...:     def __init__(cls, name, bases, attrs):
...:         super(HelloMeta2, cls).__init__(name, bases, attrs)
...:         attrs_ = {}
...:         for k, v in attrs.items():
...:             if not k.startswith('__'):
...:                 attrs_[k] = v
...:         setattr(cls, '_new_dict', attrs_)
...:
...:

别往下看。思考下这样创建出来的类有什么特殊的地方?

我揭晓一下(这次使用Python 3语法):

In : class New_Hello2(metaclass=HelloMeta2):
...:     a = 1
...:     b = True

In : New_Hello2._new_dict
Out: {'a': 1, 'b': True}

In : h2 = New_Hello2()

In : h2._new_dict
Out: {'a': 1, 'b': True}

有点明白么?其实就是在创建类的时候把类的属性循环了一遍把不是__开头的属性最后存在了_new_dict上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python——元类 的相关文章

  • (discord.py) 尝试更改成员角色时,“用户”对象没有属性“角色”

    因此 我正在尝试编写一个机器人 让某人在命令中指定的主持人指定的一段时间内暂停角色 我知道该变量称为 小时 即使它目前以秒为单位 我稍后会解决这个问题 基本上 它是由主持人在消息 暂停 personmention numberofhours
  • Python BigQuery 存储。并行读取多个流

    我有以下玩具代码 import pandas as pd from google cloud import bigquery storage v1beta1 import os import google auth os environ G
  • 如何在Windows上模拟socket.socketpair

    标准Python函数套接字 套接字对 https docs python org 3 library socket html socket socketpair不幸的是 它在 Windows 上不可用 从 Python 3 4 1 开始 我
  • __del__ 真的是析构函数吗?

    我主要用 C 做事情 其中 析构函数方法实际上是为了销毁所获取的资源 最近我开始使用python 这真的很有趣而且很棒 我开始了解到它有像java一样的GC 因此 没有过分强调对象所有权 构造和销毁 据我所知 init 方法对我来说在 py
  • 从 scikit-learn 导入 make_blobs [重复]

    这个问题在这里已经有答案了 我收到下一个警告 D Programming Python ML venv lib site packages sklearn utils deprecation py 77 DeprecationWarning
  • 使用 Pycharm 在 Windows 下启动应用程序时出现 UnicodeDecodeError

    问题是当我尝试启动应用程序 app py 时 我收到以下错误 UnicodeDecodeError utf 8 编解码器无法解码位置 5 中的字节 0xb3 起始字节无效 整个文件app py coding utf 8 from flask
  • IRichBolt 在storm-1.0.0 和 pyleus-0.3.0 上运行拓扑时出错

    我正在运行风暴拓扑 pyleus verbose local xyz topology jar using storm 1 0 0 pyleus 0 3 0 centos 6 6并得到错误 线程 main java lang NoClass
  • feedparser 在脚本运行期间失败,但无法在交互式 python 控制台中重现

    当我运行 eclipse 或在 iPython 中运行脚本时 它失败了 ascii codec can t decode byte 0xe2 in position 32 ordinal not in range 128 我不知道为什么 但
  • python 集合可以包含的值的数量是否有限制?

    我正在尝试使用 python 设置作为 mysql 表中 ids 的过滤器 python集存储了所有要过滤的id 现在大约有30000个 这个数字会随着时间的推移慢慢增长 我担心python集的最大容量 它可以包含的元素数量有限制吗 您最大
  • Pandas Dataframe 中 bool 值的条件前向填充

    问题 如何转发 fill boolTruepandas 数据框中的值 如果是当天的第一个条目 True 到一天结束时 请参阅以下示例和所需的输出 Data import pandas as pd import numpy as np df
  • 当玩家触摸屏幕一侧时,如何让 pygame 发出警告?

    我使用 pygame 创建了一个游戏 当玩家触摸屏幕一侧时 我想让 pygame 给出类似 你不能触摸屏幕两侧 的错误 我尝试在互联网上搜索 但没有找到任何好的结果 我想过在屏幕外添加一个方块 当玩家触摸该方块时 它会发出警告 但这花了很长
  • Python - 按月对日期进行分组

    这是一个简单的问题 起初我认为很简单而忽略了它 一个小时过去了 我不太确定 所以 我有一个Python列表datetime对象 我想用图表来表示它们 x 值是年份和月份 y 值是此列表中本月发生的日期对象的数量 也许一个例子可以更好地证明这
  • 为美国东部以外地区的 Cloudwatch 警报发送短信?

    AWS 似乎没有为美国东部以外的 SNS 主题订阅者提供 SMS 作为协议 我想连接我的 CloudWatch 警报并在发生故障时接收短信 但无法将其发送到 SMS YES 经过一番挖掘后 我能够让它发挥作用 它比仅仅选择一个主题或输入闹钟
  • 如何在 Django 中使用并发进程记录到单个文件而不使用独占锁

    给定一个在多个服务器上同时执行的 Django 应用程序 该应用程序如何记录到单个共享日志文件 在网络共享中 而不保持该文件以独占模式永久打开 当您想要利用日志流时 这种情况适用于 Windows Azure 网站上托管的 Django 应
  • 检查所有值是否作为字典中的键存在

    我有一个值列表和一本字典 我想确保列表中的每个值都作为字典中的键存在 目前我正在使用两组来确定字典中是否存在任何值 unmapped set foo set bar keys 有没有更Pythonic的方法来测试这个 感觉有点像黑客 您的方
  • glpk.LPX 向后兼容性?

    较新版本的glpk没有LPXapi 旧包需要它 我如何使用旧包 例如COBRA http opencobra sourceforge net openCOBRA Welcome html 与较新版本的glpk 注意COBRA适用于 MATL
  • 用于运行可执行文件的python多线程进程

    我正在尝试将一个在 Windows 上运行可执行文件并管理文本输出文件的 python 脚本升级到使用多线程进程的版本 以便我可以利用多个核心 我有四个独立版本的可执行文件 每个线程都知道要访问它们 这部分工作正常 我遇到问题的地方是当它们
  • 循环标记时出现“ValueError:无法识别的标记样式 -d”

    我正在尝试编码pyplot允许不同标记样式的绘图 这些图是循环生成的 标记是从列表中选取的 为了演示目的 我还提供了一个颜色列表 版本是Python 2 7 9 IPython 3 0 0 matplotlib 1 4 3 这是一个简单的代
  • 在 Python 类中动态定义实例字段

    我是 Python 新手 主要从事 Java 编程 我目前正在思考Python中的类是如何实例化的 我明白那个 init 就像Java中的构造函数 然而 有时 python 类没有 init 方法 在这种情况下我假设有一个默认构造函数 就像
  • Pandas 与 Numpy 数据帧

    看这几行代码 df2 df copy df2 1 df 1 df 1 values 1 df2 ix 0 0 我们的教练说我们需要使用 values属性来访问底层的 numpy 数组 否则我们的代码将无法工作 我知道 pandas Data

随机推荐

  • HX711称重模块的使用

    HX711称重模块的使用 先贴一段文字 见多了可以跳过直接看下面 满量程输出电压 激励电压 灵敏度1 0mv v 例如 供电电压是5v 乘以灵敏度1 0mv v 满量程5mv 相当于有5Kg 重力产生时候产生5mV 的电压 2 概述 711
  • C++_tuple, tie, std::get<>

    catalog std get lt gt tuple源码 tie 用处 简化比较 std get lt gt 要么返回的是 引用 要么返回的是 const 常量引用 即 std get lt 0 gt t 他返回的 一定是 t这个tupl
  • Linux新手入门教程

    下面给你讲解新手第一次接触Linux操作系统 一 学习Linux 1 Linux系统 Linux命令 ssh websever apache MySQL 缓存 PHP Python java 必备服务 2 Linux能做什么 企业服务器 嵌
  • 开发者营地

    本文聚焦于Glide的源码 基于Glide4 11 0 一 简介 Glide的GitHub Glide是一个快速高效的Android图片加载库 注重于平滑的滚动 Glide提供了易用的API 高性能 可扩展的图片解码管道 decode pi
  • WebSocket学习

    从搜索引擎搜索资料 https www runoob com html html5 websocket html WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议 WebSocket 使得客户端和
  • ISO/OSI七层模型

    想要让两台PC进行通信 必须使用相同的信息交换规则 我们把计算机网络中用于规定信息的格式 以及如何发送和接受信息的一套规则称谓网络协议或者通信协议 我们为了减少网络设计的复杂 人们按功能将计算机网络划分为多个不同功能的层 网络体系结构就是网
  • 游戏的基础—三消-1

    三消 简单的理解就是3个在一起就消喽 这里我们就最简单的操作的三消为例 就是你触屏按下去 然后以当前的位置像周围4个方向寻找是否有相同类型的游戏实体 如果有的话 把它存进一个list的里面 这里要强调一下c 里面数组一般用list因为lis
  • 字节(飞书)暑期实习面试记录

    字节一面 2022 05 07 20 00 21 20 前导 面试官简单介绍字节和面试注意点 1 自我介绍 问实习能多久 2 项目介绍部分 问 实习了多久 介绍项目 项目收获 项目难点 怎样轮询日志的 因为我项目介绍时候有提到 3 正片开始
  • 软考-信息管理——学习笔记_证

    前言 学习方法 应该达到 按照一级标题进行默写罗列 再默写二级标题默写罗列 最后按三级标题及知识点进行罗列 合同和法律篇 中标通知书发送30天内需签订合同 标底保密 招标文件发布起到截止日不得少于20天 不用招标的场景 需要采用不可代替的专
  • Eolink 旗下网关产品各版本功能及性能对比

    GoKu 网关提供企业版 EE 与开源版 CE 两个版本 满足不同阶段用户对于微服务的需求 两个版本均支持 私有云部署 开源版 CE 目前已停止维护 Apinto 开源版本是 Goku 开源版 CE 的一次架构升级 经过前面几年的网关架构和
  • 图像识别技术

    目录 1 什么是图像识别 2 图像识别的发展过程 3 图像识别的原理 4 图像识别的应用领域 5 图像识别未来的发展趋势 1 什么是图像识别 图像识别 又称为计算机视觉 是指利用计算机和人工智能技术对图像进行分析和理解 以自动识别和分类图像
  • Java并发之锁

    Java并发之锁 一 临界区 二 线程安全 三 解决临界区线程安全问题 四 Java对象头 五 重量级锁 Monitor 5 1 synchronized 5 1 1 synchronized加锁流程 六 轻量级锁 6 1 轻量级锁加锁流程
  • 信息收集的一些文件泄露

    1 robots txt文件泄露 放在网站的跟目录下 用于限制浏览器的访问 哪些可以抓取 哪些不能抓取 用于防止黑客 但是任何人可在url中直接通过 robots txt访问 导致网站结构被泄露 可对admin等重要文件设置密保保护 或者采
  • 【Python打包成exe方法】——已解决导入第三方包无法打包的问题​

    前言 在我们写代码的过程中 我们开发的脚本一般都会用到一些第三方包 可能别人也需要用到我们的脚本 如果我们将我们的xx py文件发给他 他是不能直接用的 他还需要安装python解释器 甚至还要安装我们用的那些第三方包 是不是有点小麻烦 但
  • Openmmlab(一)

    计算机视觉为研究如何自动理解图像和视频中的内容 运用于图像识别 人脸识别 计算机视觉应用 动漫特效 图像生成 风格迁移 虚拟主播 视频自动剪辑等 今日的计算机视觉 文字描述生成图片 视觉大模型 神经渲染CityNeRF 开源成为人工智能领域
  • js逆向webpack

    扣代码会遇到的基本2种形式 1 webpack function x 这里的x是存放模块1 模块2那个数组 function xx yy yy是存放模块1 模块2的数组下标 x yy call 模块参数1 模块参数2 模块参数3 必有一个加
  • 双系统ubuntu20.04(neotic版本)从0实现Gazebo仿真slam建图

    双系统ubuntu20 04 neotic版本 从0实现Gazebo仿真slam建图 昨晚完成了ROS的多机通讯 还没来得及整理相关操作步骤 在进行实际小车的实验之前 还是先打算在仿真环境中进行测试 熟悉相关的操作步骤 计划通过虚拟机 笔记
  • 【实验分享】CCIE—BGP反射器实验

    实验目的 l掌握BGP反射器的运行原理 l理解反射器的用途以及好处 实验说明 l通过此实验练习 可以灵活的使用BGP反射器 实验环境 l三台支持SPSERVICES的IOS的路由器 l直通线 实验拓扑 实验步骤 R1 config inte
  • alibaba fastjson jsonarray转list

    String avatar teacherEntity getAvatar if StringUtils isEmpty avatar List
  • Python——元类

    作者 小明 链接 https zhuanlan zhihu com p 30861351 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 什么是元类 理解元类 metaclass 之前 我们先了解下Pytho