(Python):元类(metaclass), Type类,类实例,dataclass

文章目录

    • 类实例
      • 类成员变量与成员变量的区别
    • Type类
    • Metaclass
      • ABCMeta
    • dataclass

类实例

在python中,所有的类都是一个实例,也就是说,所有的类其实都是由自己的属性和方法的。
这里就需要区分清楚一件事,类实例和对象。类实例指的是类本身,而对象则是类的某一个实例。

class Test:pass
x = Test()
print(Test, x)

其中x是Test的对象,而Test本身是类实例。

类成员变量与成员变量的区别

既然类本身是一个实例,那么类实例本身也有自己的成员变量。我们厂有一种错觉认为类实例的成员变量会被分配给每一个该类的对象,实则不然。

类成员变量属于类的属性,类的对象虽然可以访问,但是无法修改,一但对象尝试修改,Py就会自动的在对象中创建一个同名成员变量,然后赋值。此时这个对象不再访问类实例的成员变量。看下面的例子:

class test:x = Falsedef __init__(self):self.y = 2

上述中x是类变量,y是成员变量。他们有如下规则:

  1. 类变量可以通过,类和实例访问,但只允许通过类修改
  2. 如果通过实例修改类变量,则会自动在实例的作用于域中创建一个对应的成员变量
class test:ok = True@classmethoddef change_ok(cls):cls.ok = Falsex, y = test(), test()print('x, y分别是', x.ok, y.ok)
x.change_ok()
print('x, y分别是', x.ok, y.ok)
x.ok = True
print('x, y分别是', x.ok, y.ok)
x.change_ok()
print('x, y分别是', x.ok, y.ok)
"""
output:
x, y分别是 True True
x, y分别是 False False
x, y分别是 True False
x, y分别是 True False
"""

我们一步一步来看输出:

  1. 首先由于x和y都是test的实例,所以在访问ok时都访问的是类变量ok
  2. 改变类变量ok,由于x和y都访问的是类变量,所以两者同时该变
  3. 为修改x的ok为True,此时Python自动为x的成员变量区域创建一个ok变量,从此之后x不再访问公共类变量ok,而是自己独有的成员变量ok。
  4. 改变类变量ok,此时x已经不会再跟着变了,因为x有了自己的成员变量ok

类变量只能通过类对象访问,而类对象通过:类名.xxx,cls.xxx的方式使用。类对象全局唯一。

Type类

上面讲完了类实例,那么问题来了,Py的类都是一个实例,那么谁创造这些实例呢?
没错,就是Type类创造的,Type类创造了所有的类实例,所有的类实例都是Type的一个instance,看下面代码:

class Test:pass
print(isinstance(object, type))
print(isinstance(Test, type))

输出结果均为True,可以见得所有的类都是type类的一个对象。那么是否可以通过type类来创建一个新的类呢?
当然可以!
我们可以通过如下方法来动态的创建一个类

type(类名, (父类们), 所有属性)

举个例子:

@classmethod
def speak(cls, x):print(x)
T = type('Myclass', (object,), {'speak': speak})
T.speak(123123)
print(T)
"""
output:
123123
<class '__main__.Myclass'>
"""

可以看到我们通过type方法创建了一个类Myclass,还为其设置了一个类方法speak。而这里类名,父类,类属性都是通过参数传入的,所以这是一个动态创建类的过程。

我们甚至可以进一步的把它扩展。我们可以把一个类存在文本文件中,我们通过读取文本文件来创建类。

x = """
@classmethod
def speak(cls, x):print(x)
"""
attr_ = dict()
exec(x, globals(), attr_)T = type('Myclass', (object,), attr_)
T.speak(123123)
print(T)

exec可以动态的执行文本代码,第一个参数是代码,第二个参数需要传入一个变量作用区域(字典),第三个参数是变异的结果存储的结果(一个Mapping类型)。然后把这个结果传给type就创建出来的一个类。通过这种方式,我们甚至可以在线的创建一些类,更新一些操作。

Metaclass

每一个类都会有一个Metaclass,这个Metaclass就是用来创建自身类的实例的,如果没有指明Metaclass,那么这个值默认就是type。这也就是为什么每一个类的实例都是type的对象的原因。

那么,我们是否可以定义属于自己的Metaclass呢?当然是可以的,只需要继承type类即可。作为Metaclass,其负责的内容是创建类对象,所以我们需要重写__new__方法。例如:

class MyMetaclass(type):@classmethoddef __new__(mcs, *args, **keywords):return super().__new__(*args) # 创建类实例class Test(metaclass=MyMetaclass):# (使用MyMetaclass作为元类)pass

由于这里我们是在创建一个类,所以我们可以搞一些小动作,比如给其添加一些类属性:

class MyMetaclass(type):@classmethoddef __new__(mcs, *args, **keywords):class_ = super().__new__(*args)class_.meta_type = 'MyMetaclass'return class_class Test(metaclass=MyMetaclass):passprint(Test.meta_type)
"""
MyMetaclass
"""

我们还可以像Metaclass中传入参数,使得在创建类时多一些选择

class MyMetaclass(type):@classmethoddef __new__(mcs, *args, **keywords):class_ = super().__new__(*args)for key, value in keywords.items():setattr(class_, key, value)return class_class Test(metaclass=MyMetaclass, name='test'):pass
print(Test.name)

上述的输出结果为test。

ABCMeta

ABCMeta是官方提供的一个抽象方法元类,使用它我们就可以定义类接口。其使用方法如下:

  1. 类Test使用ABCMeta为元类
  2. 使用abstractmethod,abstractstaticmethod等装饰器来装饰Test的成员方法,使其成为抽象方法。

这样拥有抽象方法的Test类就无法实例化,而想要实例化就必须继承且实现对应的类

from abc import ABCMeta, abstractmethod, abstractpropertyclass Test(metaclass=ABCMeta):@abstractmethoddef speak(self, x):...@abstractpropertydef name(self):...Test()
"""
Traceback (most recent call last):File "e:\PythonProject\main.py", line 68, in <module>       Test()
TypeError: Can't instantiate abstract class Test with abstract methods name, speak
"""

如果想要使用这个函数,就必须继承然后实现,这就使得我们可以强迫使用者实现某些方法。

from abc import ABCMeta, abstractmethod, abstractpropertyclass Test(metaclass=ABCMeta):@abstractmethoddef speak(self, x):...@abstractpropertydef name(self):...class RealTest(Test):def speak(self, x):print(x)@propertydef name(self):return 'RealTest'RealTest()

此时RealTest就可以正常的实例化了,因为所有的抽象方法,属性都已经被实现。

dataclass

dataclass是py提供的一种数据接口,我们可以通过它来定义数据类,我们通过类装饰器的方式来装饰类就可以把类变成数据类

from dataclasses import dataclass, field@dataclass()
class MyData:age: intname: str = 9print(MyData(10))
"""
MyData(age=10, name=9)
"""

数据类内部,我们可写上若干种数据的定义,然后在创建时只需要输入参数就可以创建。
dataclass为我们写好了各种常见的操作,例如__eq__, __rper__, __str__等。

from dataclasses import dataclass, field@dataclass()
class MyData:age: intname: str = 9print(MyData(10) == MyData(10))
"""
True
"""

我们还可以指定这些参数是否可以被二次修改,例如:

from dataclasses import dataclass, field@dataclass(frozen=True)
class MyData:age: intname: str = 9x = MyData(10)
x.age = 100
"""
Traceback (most recent call last):File "e:\PythonProject\main.py", line 45, in <module>x.age = 100File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'age'
"""

此时加了frozen=True参数,所以修改就会报错。

我们还可以隐藏某些我们不想让用户看到的参数,此时使用filed函数。

from dataclasses import dataclass, field@dataclass
class MyData:age: intname: str = field(default='Mydata', init=False, hash=True, repr=False)x = MyData(10)

上述代码使用field函数给了name变量值,同时设置其不能通过对象来赋值,也不能被print打印出来,但是可以参与hash。

除此之外,dataclass还提供了__post__init__操作为初始化之后的操作进行一些后处理

from dataclasses import dataclass, field
@dataclass(order=True) # 设置该Class支持排序
class MyData:age: intname: str = 9other_info: list = field(default=None, init=False, repr=True, hash=True)def __post_init__(self): # 后续操作,根据age处理斌生成other_infoif self.age >= 18:self.other_info = "this person has matured"else:self.other_info = "this person has not matured"x = MyData(10, 'asd')
y = MyData(20, 'asssd')
print(sorted([y, x])) # 排序MyData
"""
[MyData(age=10, name='asd', other_info='this person has not matured'), MyData(age=20, name='asssd', other_info='this person has matured')]
"""

最后一点就是,dataclass还支持排序操作,按照的排序的优先级是变量的顺序。

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

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

相关文章

使用vim-cmd工具给ESXi虚机定期打快照

VMware虚拟化 - 建设篇 第四章 使用vim-cmd工具给ESXi虚机定期打快照 VMware虚拟化 - 建设篇系列文章回顾使用vim-cmd工具给ESXi虚机定期打快照前言前提条件ESXi新增执行快照备份的sh脚本ESXi添加crond任务并使其生效ESXi指定部分虚拟机不执行定期快照(附加)虚拟机自定义属性…

ChatGPT有几个版本,哪个版本最强,如何选择适合自己的?

​ChatGPT就像内容生产界的瑞士军刀。它可以是数学导师、治疗师、职业顾问、编程助手&#xff0c;甚至是旅行指南。只要你知道如何让它做你想做的事&#xff0c;ChatGPT几乎可以提供你要的任何东西。 但重要的是&#xff0c;你知道哪个版本的ChatGPT最能满足你的需求吗&#x…

Windows 11 下 OpenFace 2.2.0 的安装

写在前面 最近需要做关于面部的东西&#xff0c;所以需要使用到OpenFace这个工具&#xff0c;本文仅用来记录本人安装过程以供后续复现&#xff0c;如果可以帮助到读者也是非常荣幸。 安装过程 不编译直接使用 这种方法可以直接从官方下载下来编译好的exe以及gui进行使用&a…

在 “小小容器” WasmEdge 里运行小小羊驼 llama 2

昨天&#xff0c;特斯拉前 AI 总监、OpenAI 联合创始人 Andrej Karpathy 开源了 llama2.c 。 只用 500 行纯 C 语言就能训练和推理 llama 2 模型的框架&#xff0c;没有任何繁杂的 python 依赖。这个项目一推出就受到大家的追捧&#xff0c;24 小时内 GitHub 收获 4000 颗星&am…

Codeforces Round 889 (Div. 2) (C1~C2)

掉大分&#xff0c;C1被sb错误困扰。 提示如果C1会了但不会C2,也应该先将C1解法看一遍 C1 Dual (Easy Version) 题意 给定长度为 n n n 的数组 a a a&#xff0c;&#xff08; n < 20 &#xff0c; − 20 < a i < 20 n<20&#xff0c;-20<a_i<20 n&l…

KY222 打印日期+KY111日期差值

一、KY222题目 二、代码 #include <climits> #include <iostream> using namespace std; class Date{public:Date(int year 1,int month 2,int day 3){_year year;_month month;_day day;}int GetDay(int year ,int month);void Define(int n);public:int _yea…

查看进程方式

目录 ps top uptime pstree ps 查看静态的进程统计信息 top 实时显示系统中各个进程的资源占用情况 第一行 top - 17:00:23 up 15 min, 1 user, load average: 1.05, 1.22, 0.98 17:00:23————当前时间 up 15 min————系统运行时间 1 user————当前登录用户数…

陪诊小程序软件|陪诊系统定制|医院陪诊小程序

开发一个陪诊小程序需要投入一定的费用&#xff0c;具体金额会因项目的复杂程度、功能需求和推广政策而有所差异在投入资金之前&#xff0c;建议进行市场调研和需求分析&#xff0c;制定出合理的预算&#xff0c;并选择专业的开发团队进行合作&#xff0c;那么开发陪诊小程序需…

django模板继承和组件了解

1、模板继承 什么时候需要用到模板呢&#xff0c;比如我们在开发的页面的导航栏&#xff0c;你点不同的功能页面这个导航栏都是一样的&#xff0c;如果每个页面都要加上这个导航条会写重复代码&#xff0c;而且如果导航条有变化&#xff0c;每个页面都要修改&#xff0c;这个是…

linux虚拟机开机后桌面显示CentOS-7.5-x86盘片文件,并且无法远程连接虚拟机?

在虚拟机启动后遇到了显示CentOS-7.5-x86光盘片文件的问题&#xff0c;并且无法远程连接到虚拟机&#xff0c;有几个可能的解决方法&#xff1a; 检查虚拟机设置&#xff1a;确保虚拟机的网络适配器已正确配置&#xff0c;并且虚拟机配置的网络选项是桥接模式或 NAT 模式&#…

2023大同首届信息技术产业峰会举行,共话数字经济新未来

7月28日&#xff0c;“聚势而强共领信创”2023大同首届信息技术产业峰会圆满举行。本次峰会由中共大同市委、大同市人民政府主办&#xff0c;中国高科技产业化研究会国际交流合作中心、山西省信创协会协办&#xff0c;中共大同市云冈区委、大同市云冈区人民政府、诚迈科技&…

密码学的一些常识

1&#xff0c;对称密码、公钥密码、消息认证、数字签名的对比 对称密码公钥密码发送者共享秘钥加密公钥加密接收者共享秘钥解密私钥解密秘钥配送问题存在不存在&#xff0c;但需要CA认证公钥机密性√√ 消息认证数字签名发送者共享秘钥计算MAC使用私钥对文本HASH值做签名接收者…

在Spring Boot中打印SQL语句的方法

系列文章目录 文章目录 系列文章目录前言一、使用Spring Boot的配置选项打印SQL语句二、 使用Logback配置打印SQL语句三、 使用Druid数据源打印SQL语句四、 使用Log4j2打印SQL语句五、 使用@EventListener监听SQL语句总结前言 在Spring Boot项目中,调试和优化数据库操作是很常…

微积分物理题(原创)

在一个粗糙的平面上&#xff0c;有一个质量为 1 kg 1\text{kg} 1kg的小木块&#xff0c;小木块的初速度为 0 0 0&#xff0c;小木块与平面的动摩擦因数 μ 0.2 \mu0.2 μ0.2。有一个拉力 F F F拉动小木块从左往右移动&#xff0c;拉力 F F F与时间 t t t的关系为 F 0.3 t 2 −…

ES6 新特性(详细复习笔记)--下

文章目录 ES6 新特性(详细复习笔记)-下对象相关新特性1. 需求: 演示声明对象简写2-需求: 演示对象方法简写3-应用实例-对象拓展运算符 注意事项和使用细节箭头函数基本介绍应用实例 1-箭头函数使用应用实例 2-箭头函数使用应用实例 3-箭头函数对象解构 注意事项和使用细节综合代…

打卡力扣题目五

#左耳听风 ARST 打卡活动重启# 目录 一、问题 二、解题方法一 三、解题方法二 四、两种方法的区别 关于 ARTS 的释义 —— 每周完成一个 ARTS&#xff1a; ● Algorithm: 每周至少做一个 LeetCode 的算法题 ● Review: 阅读并点评至少一篇英文技术文章 ● Tips: 学习至少一个…

Jgit 工具类 (代码检出、删除分支(本地、远程)、新建分支、切换分支、代码提交)

https://blog.csdn.net/qq_37203082/article/details/120327084 Jgit 工具类 (代码检出、删除分支&#xff08;本地、远程&#xff09;、新建分支、切换分支、代码提交)_jgit删除远程分支_CJ点的博客-CSDN博客 <!--JAVA操作GIT--><dependency><groupId>org.…

JavaScript学习 -- SM3算法基本原理

SM3算法是一种由国家密码管理局发布的哈希算法&#xff0c;被广泛用于数字签名和消息认证等应用中。在JavaScript中&#xff0c;我们可以使用第三方库来计算数据的SM3哈希值。本篇文章将介绍SM3算法的基本原理和相关技术&#xff0c;并提供一些实例来演示如何在JavaScript中使用…

vue3 中模板字符串中添加click方法并传参

工作中遇到html字符串拼接出dom结构&#xff0c;并且需要触发事件和传参的场景。借此机会记录一下。 1. 拼接内容 核心是利用html的onClick属性&#xff0c;触发单击事件&#xff0c;想要传递对象&#xff0c;必须要JSON.stringify()&#xff0c;否则控制台会报错 // 传递对象…

DAY14_FilterListenerAjaxAxiosJsonfastjson综合案例-axios和html交互

目录 1 Filter1.1 Filter概述1.2 Filter快速入门1.2.1 开发步骤1.2.2 代码演示 1.3 Filter执行流程1.4 Filter拦截路径配置1.5 过滤器链1.5.1 概述1.5.2 代码演示1.5.3 问题 1.6 案例1.6.1 需求1.6.2 分析1.6.3 代码实现1.6.3.1 创建Filter1.6.3.2 编写逻辑代码1.6.3.3 测试并抛…