Python进阶之元类

Python进阶之元类

目录
什么是元类?
元类的调用流程
根据类自定义元类
__new__方法以及参数
----------cls
----------name
----------bases
----------attrs
__call__方法
生成对象的完整代码

什么是元类?

在python面向对象中,我们知道所有的新式类都会继承object类,但是object类又是从何而来呢?是否所有的类在构建之前都会有一个框架呢?

为了方便理解我们直接上代码:

class MyClass(object):passprint(type(MyClass()))
# <class '__main__.MyClass'>
# 类的实例对象属于 MyClassprint(type(MyClass))
# <class 'type'>
# 发现类的对象属于 typeprint(type(int))
# <class 'type'>
# 发现int类也属于 typeprint(type.__base__)
# <class 'object'>
# 发现其父类是 object

根据我们已学的知识1和4不难理解,那么这个type又是什么呢?

object,class,type三者之间的关系:

  • object:object类是所有类(class)的父类,包括type类,并且object没有父类

  • class:class继承自object类,同时由type进行实例化。其中,type就是我们所要讲的元类(MetaClass)

  • type:type类是所有类的类型,即为所有类(class)都可由type实例化而来,包括object类,甚至其type本身也是由它初始化的

元类的调用流程

知道了什么是元类,那么他的调用流程也必然是我们需要知道的

在我们平时构造类时,类就是实例化对象的模板__init__初始化的则是对象的属性

那么相同的,类是由元类(MetaClass)创建的,那么元类便是类的模版

大致的调用流程图解:

image-20240108212405346

根据类自定义元类

class MyMeta(type):def __new__(cls, name, bases, attrs):# 在类创建之前执行一些操作# 可以修改类的属性和方法# 可以添加额外的属性和方法return super().__new__(cls, name, bases, attrs)class MyClass(metaclass=MyMeta):pass

在python中我们需要用到__new__()特殊方法来在对象创建之前让其经过自定义元类MyMeta(type)调用

大白话就是我们自建了一个元类,并且继承type以便调用它的特殊方法,上面的代码中我们重写了__new()__方法,接下来我们只需要在方法中对参数(cls, name, bases, attrs)进行操作即可

__new__方法以及参数

所有参数名

cls

class MyMeta(type):def __new__(cls, name, bases, attrs):print(cls) # 输出:<class '__main__.MyMeta'>print(cls.__name__) # 输出:MyMetareturn super().__new__(cls, name, bases, attrs)class My(object, metaclass=MyMeta):def __init__(self, name):self.name = namem = My('张三')

name

class MyMeta(type):def __new__(cls, name, bases, attrs):print(name) # 输出:MyClassif len(name) > 3:print("你好", end='')return super().__new__(cls, name, bases, attrs)class MyClass(object, metaclass=MyMeta):def __init__(self, name):self.name = namem = MyClass('张三')
print(m.name)
# MyClass
# 你好张三

bases

class MyMeta(type):def __new__(cls, name, bases, attrs):print(bases) # 输出:(<class '__main__.Parent'>,)return super().__new__(cls, name, bases, attrs)class Parent:passclass MyClass(Parent, metaclass=MyMeta):def __init__(self, name):self.name = namem = MyClass('张三')

attrs

class MyMeta(type):def __new__(cls, name, bases, attrs):# 修改属性attrs['modified_attr'] = 100 # 新增键modified_attrprint(attrs) # {'__module__': '__main__', '__qualname__': 'MyClass', 'original_method': <function MyClass.original_method at 0x000001B3618A1800>, 'modified_attr': 100} # 修改方法def modified_method(self):return "方法2"attrs['modified_method'] = modified_methodprint(attrs)return super().__new__(cls, name, bases, attrs)class MyClass(metaclass=MyMeta):def original_method(self):return "方法1"# 测试示例
my_obj = MyClass()
print(my_obj.modified_attr)  # 输出: 100
print(my_obj.original_method())  # 输出: 方法1
print(my_obj.modified_method())  # 输出: 方法2

__call__方法

在实例化对象的时候,会自动触发类中的__new__方法执行其中的代码,并且触发__init__方法进行初始化属性。那么此时不得不思考一个问题:为什么类会先调用__new__再调用__init__?是谁在控制这个流程?

-----__call__

调用类就是调用类的 __call__方法,类调用后的运行逻辑,其实都是 call 方法来控制的

__call__方法可以将函数或者类都转换成可调用对象,也就是我们平时调用函数时在后面加的括号:

# 函数中使用__call__
def text():print("你好")text() # 你好
text.__call__() # 你好
# 类中使用__call__
class MyClass():def __call__(self, *args, **kwargs):print('你好')my_obj = MyClass()
my_obj() # 你好

在元类中我们可以利用重写__call__方法来满足我们特定的需求:

class MyMeta(type):def __call__(cls, *args, **kwargs):print("重写__call__方法")return 123123class MyClass(metaclass=MyMeta):passmy_obj = MyClass()
print(my_obj)# 输出:123123# 用__call__方法判断类名是否为大写
class MyMeta(type):def __call__(cls, *args, **kwargs):if cls.__name__.isupper():print('is upper')else:print('is not upper')return super().__call__(*args, **kwargs)class MYCLASS(metaclass=MyMeta):passclass myclass(metaclass=MyMeta):passmy_obj = MYCLASS()  # is upper
my_obj2 = myclass()  # is not upper

__call__的执行流程:

image-20240109121001606

生成对象的完整代码

class MyMeta(type):def __new__(cls, *args, **kwargs):print("type调用了MyMeta的__new__方法,并且返回了一个对象,该对象即MyClass")return super().__new__(cls, *args, **kwargs)def __call__(cls, *args, **kwargs):print("这里调用了MyMeta的__call__方法,在这里可以对MyClass生成的对象a进行额外的操作,最终返回初始化好的对象a")instance = super().__call__(*args, **kwargs)return instancedef __init__(cls, what, bases=None, dict=None):print("当前接受的cls对象即MyClass,这里不重写直接继承并初始化数据")super(MyMeta, cls).__init__(what, bases, dict)class MyClass(metaclass=MyMeta):def __init__(self, age, name=None):self.name = name# 创建一个可调用对象
a = MyClass(18, name='张三')
t__(cls, what, bases=None, dict=None):print("当前接受的cls对象即MyClass,这里不重写直接继承并初始化数据")super(MyMeta, cls).__init__(what, bases, dict)class MyClass(metaclass=MyMeta):def __init__(self, age, name=None):self.name = name# 创建一个可调用对象
a = MyClass(18, name='张三')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/608151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI大语言模型会带来了新一波人工智能浪潮?

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

自动化测试最佳实践:有效利用 ForEach 循环技巧

在 自动化测试 场景中&#xff0c;当需要对数组内的所有元素分别执行特定操作时&#xff0c;我们通常会采用 ForEach 循环 来实现这一过程。例如一个常见的场景&#xff1a;请求一个获取宠物列表的接口&#xff0c;返回了 n 个宠物的 id &#xff0c;然后根据这些宠物 id 逐一查…

mongodb学习篇

目录 前言基本概念数据库-database集合-collection文档-document 部署mongodblinux安装mongodbdocker安装mongodb MongoDB Shell (mongosh)命令行工具mongodb可视化-mongodb-compass、mongo-expressmongodb配置文件mongodb库、集合、文档库基本操作集合基本操作文档的增删改查C…

世微AP3464 车充专用芯片 4-30V输入 ADJ可调/2.4A输出降压驱动芯片

AP3464 是一款支持宽电压输入的同步降压 电源管理芯片&#xff0c;输入电压 4-30V 范围内可实现 2.4A 的连续电流输出。通过调节 FB 端口的分压 电阻&#xff0c;设定输出 1.8V 到 28V 的稳定电压。 AP3464 具有的恒压/恒流(CC/CV)特性。 AP3464 采用电流模式的环路控制原理&am…

获取小红书笔记详情API调用说明(含请求示例参数说明)

前言 小红书&#xff0c;是一个引领全球时尚潮流的社交电商平台。在这里&#xff0c;你可以发现世界各地的优质好物&#xff0c;从美妆护肤、穿搭时尚&#xff0c;到家居生活、旅行美食&#xff0c;一切应有尽有。同时&#xff0c;这里也是一个分享生活点滴的平台&#xff0c;…

sonarqube配置本地扫描代码

一、本地maven设置setting文件&#xff1a; 1&#xff09;添加pluginGroup <pluginGroups><pluginGroup>org.sonarsource.scanner.maven</pluginGroup></pluginGroups> 2&#xff09;添加profile&#xff1a; <profile><id>sonar</i…

有趣的前端知识(二)

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读HTML元素元素属性头部元素列表元素区块元素表单元素 颜色字符实体 HTML元素 …

知识点整理[(GraphGeo)RELATED WORK]

2 RELATED WORK 2.1 IP Geolocation 问题一:IP定位预测方法之一:Data mining-based methods 回答: 依赖于在公开的资源中挖掘位置线索来对目标IP(target IP)进行地理定位。其中一些数据分析了来自与IP相关的数据库,如WHOIS数据库和DNS的数据。 (1)例如,Moore等…

neo4j图数据库的简单操作记录

知识图谱文件导出 首先停止运行sudo neo4j stop然后导出数据库 导出格式为&#xff1a; 具体命令如下sudo neo4j-admin database dump --to-path/home/ neo4j最后重启sudo neo4j start知识图谱外观修改 在网页点击节点&#xff0c;选中一个表情后点击&#xff0c;可修改其颜…

Python+Flask+MySQL的图书馆管理系统【附源码,运行简单】

PythonFlaskMySQL的图书馆管理系统【附源码&#xff0c;运行简单】 总览 1、《图书馆管理系统》1.1 方案设计说明书设计目标需求分析工具列表 2、详细设计2.1 登录2.2 注册2.3 程序主页面2.4 图书新增界面2.5 图书信息修改界面2.6 普通用户界面2.7 其他功能贴图 3、下载 总览 …

【sklearn练习】preprocessing的使用

介绍 scikit-learn 中的 preprocessing 模块提供了多种数据预处理工具&#xff0c;用于准备和转换数据以供机器学习模型使用。这些工具可以帮助您处理数据中的缺失值、标准化特征、编码分类变量、降维等。以下是一些常见的 preprocessing 模块中的功能和用法示例&#xff1a; …

【CSS】CSS中的BFC,是什么?

一、常见定位方案 普通流默认&#xff0c;从上而下&#xff0c;行内元素水平排列&#xff0c;行满换行&#xff0c;块级元素渲染成一个新行。 浮动先按普通流位置出现&#xff0c;然后根据浮动方向偏移。 绝对定位元素具体位置由绝对定位坐标组成。二、什么是BFC BFC&#xff…

适合小微企业的记账软件有哪些?

“涉及了很多的库存管理、进销存和记账&#xff0c;最好是这个软件可以随时看到我们公司的财务数据&#xff0c;且一定要安全&#xff01;” 进、销、存、财……进销存财管理就像是企业的大管家&#xff0c;管着货物、资金、成本、收入&#xff0c;保证一切有序运转。这些管理…

ISIS基本概率与配置(HCIP完整版)

目录 一、ISIS协议基础 1、ISIS概述&#xff08;认识ISIS&#xff09; 2、ISIS的应用 4、ISIS的工作过程 5、ISIS路由器的类型 6、ISIS区域 7、ISIS报文 8、ISIS基础配置 9、进程号&#xff1a; 10、NET地址 11、ISIS邻居关系 二、邻居表分析 1、ISIS邻居表字段解析…

Oracle11.2.0.4从RMAN备份中快速恢复单个表的方法

文章目录 前言一、查询所要恢复的表所涉及的表空间二、创建用于恢复的数据库三、恢复步骤1.恢复控制文件2.修改redo日志名称3.表空间恢复4.表空间recover5.查询数据 前言 由于用户误操作导致某表中的数据错乱&#xff0c;导致业务不能正常使用&#xff0c;现需要将该表恢复到一…

【FPGA】分享一些FPGA数字信号处理相关的书籍

在做FPGA工程师的这些年&#xff0c;买过好多书&#xff0c;也看过好多书&#xff0c;分享一下。 后续会慢慢的补充书评。 【FPGA】分享一些FPGA入门学习的书籍【FPGA】分享一些FPGA协同MATLAB开发的书籍 【FPGA】分享一些FPGA视频图像处理相关的书籍 【FPGA】分享一些FPGA高速…

更改邮箱发件人

更改邮箱发件人 未更改前发件人显示为发件人的邮箱地址 这里以outlook邮箱为例&#xff0c;进行邮箱发件人的更改 1.点击左上角“文件”选项 2.打开“账户设置”下拉菜单中的“账户设置” 3.选择“电子邮件”&#xff0c;点击该栏下的“更改”选项 4.在弹出页面中修改你…

机器学习原理到Python代码实现之NaiveBayes【朴素贝叶斯】

Naive Bayes 朴素贝叶斯算法 该文章作为机器学习的第二篇文章&#xff0c;主要介绍的是朴素贝叶斯算法的原理和应用。学习本章内容建议对概率论中的联合概率以及先验概率、后验概率有初步的学习和掌握。 难度系数&#xff1a;⭐⭐⭐ 更多相关工作请参考&#xff1a;Github 算法…

为什么流不关闭会导致内存泄漏

引言 经常有人告诉你流用完要记得关&#xff0c;不然会导致内存泄漏&#xff0c;但你是否考虑过下面这些问题: 为什么流不关会导致内存泄漏&#xff1f;JVM不是有垃圾回收机制吗&#xff1f;这些引用我用完不就变垃圾了为什么不会被回收呢&#xff1f;流未关闭除了导致内存泄…

node的下载、安装、配置

下载&#xff1a; 官网下载&#xff1a;Node.js 左右两个都可以&#xff1a; 安装&#xff1a; 打开cmd&#xff1a; 输入以下指令&#xff0c;如果出现版本号说明安装成功 node -v npm -v 配置&#xff1a; 1、新建文件夹&#xff1a;node_cache和node_global作为npm“缓…