python入门学习笔记之元类

一文掌握Python 最难知识点:元类 前言 在学习 python 过程中想必大家都会去看源码,看源码的过程中会看到一些元类,但是看起来感觉很吃力看不懂,那是因为我们对元类不够了解。 今天我们就来聊一聊 python 元类,看看元类到底是何方神圣。 必要知识储备 ● 在讲元类之前我们得先搞清楚类和对象的概念以及类的创建过程,这个至关重要,这取决于我们是否能真正理解和正确使用元类。 ● 类和对象概念 1、类:用来描述具有相同的属性和方法的对象的集合(抽象) 2、对象:类的实体就是对象(具体)传统方式创建类 传统方式创建类 1、代 阅读详情

本节重点

  • 了解元类
  • 了解元类的用途
    本节时长需控制在45分钟内

一 知识储备

exec:三个参数

参数一:字符串形式的命令

参数二:全局作用域(字典形式),如果不指定,默认为globals()

参数三:局部作用域(字典形式),如果不指定,默认为locals()
exec的使用

#可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
g={
'x':1,
'y':2
}
l={}

exec('''
global x,z
x=100
z=200

m=300
''',g,l)

print(g) #{'x': 100, 'y': 2,'z':200,......}
print(l) #{'m': 300}

二 引子(类也是对象)

class Foo:
      pass

f1=Foo() #f1是通过Foo类实例化的对象

python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例),因而我们可以将类当作一个对象去使用,同样满足第一类对象的概念,可以:

把类赋值给一个变量

把类作为函数参数进行传递

把类作为函数的返回值

在运行时动态地创建类

上例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?

#type函数可以查看类型,也可以用来查看对象的类,二者是一样的
print(type(f1)) # 输出:<class ‘main.Foo’> 表示,obj 对象由Foo类创建
print(type(Foo)) # 输出:<type ‘type’>

三 什么是元类?

元类是类的类,是类的模板

元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为

元类的实例化的结果为我们用class定义的类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)

type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
![image_1c1p03hmh198t1skn1ulrps57h19.png-80.6kB][1]

四 创建类的两种方式

方式一:使用class关键字

class Chinese(object):
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def talk(self):
        print('%s is talking' %self.name)

方式二:就是手动模拟class创建类的过程):将创建类的步骤拆分开,手动去创建

#准备工作:

#创建类主要分为三部分

  1 类名

  2 类的父类

  3 类体


#类名
class_name='Chinese'
#类的父类
class_bases=(object,)
#类体
class_body="""
country='China'
def __init__(self,name,age):
    self.name=name
    self.age=age
def talk(self):
    print('%s is talking' %self.name)
"""

步骤一(先处理类体->名称空间):类体定义的名字都会存放于类的名称空间中(一个局部的名称空间),我们可以事先定义一个空字典,然后用exec去执行类体的代码(exec产生名称空间的过程与真正的class过程类似,只是后者会将__开头的属性变形),生成类的局部名称空间,即填充字典

class_dic={}
exec(class_body,globals(),class_dic)


print(class_dic)
#{'country': 'China', 'talk': <function talk at 0x101a560c8>, '__init__': <function __init__ at 0x101a56668>}

步骤二:调用元类type(也可以自定义)来产生类Chinense

Foo=type(class_name,class_bases,class_dic) #实例化type得到对象Foo,即我们用class定义的类Foo


print(Foo)
print(type(Foo))
print(isinstance(Foo,type))
'''
<class '__main__.Chinese'>
<class 'type'>
True
'''

我们看到,type 接收三个参数:

第 1 个参数是字符串 ‘Foo’,表示类名
第 2 个参数是元组 (object, ),表示所有的父类
第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
补充:若Foo类有继承,即class Foo(Bar):… 则等同于type(‘Foo’,(Bar,),{})

五 自定义元类控制类的行为

#一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的行为,工作流程是什么)
egon5步带你学会元类

#!!!如果你拷贝不注明出处的话,以后老子都不写了!!!

#知识储备:
    #产生的新对象 = object.__new__(继承object类的子类)

#步骤一:如果说People=type(类名,类的父类们,类的名称空间),那么我们定义元类如下,来控制类的创建
class Mymeta(type):  # 继承默认元类的一堆属性
    def __init__(self, class_name, class_bases, class_dic):
        if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():
            raise TypeError('必须为类指定文档注释')

        if not class_name.istitle():
            raise TypeError('类名首字母必须大写')

        super(Mymeta, self).__init__(class_name, class_bases, class_dic)


class People(object, metaclass=Mymeta):
    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

#步骤二:如果我们想控制类实例化的行为,那么需要先储备知识__call__方法的使用
class People(object,metaclass=type):
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __call__(self, *args, **kwargs):
        print(self,args,kwargs)


# 调用类People,并不会出发__call__
obj=People('egon',18)

# 调用对象obj(1,2,3,a=1,b=2,c=3),才会出发对象的绑定方法obj.__call__(1,2,3,a=1,b=2,c=3)
obj(1,2,3,a=1,b=2,c=3) #打印:<__main__.People object at 0x10076dd30> (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}

#总结:如果说类People是元类type的实例,那么在元类type内肯定也有一个__call__,会在调用People('egon',18)时触发执行,然后返回一个初始化好了的对象obj

#步骤三:自定义元类,控制类的调用(即实例化)的过程
class Mymeta(type): #继承默认元类的一堆属性
    def __init__(self,class_name,class_bases,class_dic):
        if not class_name.istitle():
            raise TypeError('类名首字母必须大写')

        super(Mymeta,self).__init__(class_name,class_bases,class_dic)

    def __call__(self, *args, **kwargs):
        #self=People
        print(self,args,kwargs) #<class '__main__.People'> ('egon', 18) {}

        #1、实例化People,产生空对象obj
        obj=object.__new__(self)


        #2、调用People下的函数__init__,初始化obj
        self.__init__(obj,*args,**kwargs)


        #3、返回初始化好了的obj
        return obj

class People(object,metaclass=Mymeta):
    country='China'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def talk(self):
        print('%s is talking' %self.name)

obj=People('egon',18)
print(obj.__dict__) #{'name': 'egon', 'age': 18}

#步骤四:
class Mymeta(type): #继承默认元类的一堆属性
    def __init__(self,class_name,class_bases,class_dic):
        if not class_name.istitle():
            raise TypeError('类名首字母必须大写')

        super(Mymeta,self).__init__(class_name,class_bases,class_dic)

    def __call__(self, *args, **kwargs):
        #self=People
        print(self,args,kwargs) #<class '__main__.People'> ('egon', 18) {}

        #1、调用self,即People下的函数__new__,在该函数内完成:1、产生空对象obj 2、初始化 3、返回obj
        obj=self.__new__(self,*args,**kwargs)

        #2、一定记得返回obj,因为实例化People(...)取得就是__call__的返回值
        return obj

class People(object,metaclass=Mymeta):
    country='China'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def talk(self):
        print('%s is talking' %self.name)

    def __new__(cls, *args, **kwargs):
        obj=object.__new__(cls)
        cls.__init__(obj,*args,**kwargs)
        return obj

obj=People('egon',18)
print(obj.__dict__) #{'name': 'egon', 'age': 18}

#步骤五:基于元类实现单例模式,比如数据库对象,实例化时参数都一样,就没必要重复产生对象,浪费内存
class Mysql:
    __instance=None
    def __init__(self,host='127.0.0.1',port='3306'):
        self.host=host
        self.port=port

    @classmethod
    def singleton(cls,*args,**kwargs):
        if not cls.__instance:
            cls.__instance=cls(*args,**kwargs)
        return cls.__instance


obj1=Mysql()
obj2=Mysql()
print(obj1 is obj2) #False

obj3=Mysql.singleton()
obj4=Mysql.singleton()
print(obj3 is obj4) #True

#应用:定制元类实现单例模式
class Mymeta(type):
    def __init__(self,name,bases,dic): #定义类Mysql时就触发
        self.__instance=None
        super().__init__(name,bases,dic)

    def __call__(self, *args, **kwargs): #Mysql(...)时触发

        if not self.__instance:
            self.__instance=object.__new__(self) #产生对象
            self.__init__(self.__instance,*args,**kwargs) #初始化对象
            #上述两步可以合成下面一步
            # self.__instance=super().__call__(*args,**kwargs)

        return self.__instance
class Mysql(metaclass=Mymeta):
    def __init__(self,host='127.0.0.1',port='3306'):
        self.host=host
        self.port=port


obj1=Mysql()
obj2=Mysql()

print(obj1 is obj2)

六 练习题

练习一:在元类中控制把自定义类的数据属性都变成大写

class Mymetaclass(type):
    def __new__(cls,name,bases,attrs):
        update_attrs={}
        for k,v in attrs.items():
            if not callable(v) and not k.startswith('__'):
                update_attrs[k.upper()]=v
            else:
                update_attrs[k]=v
        return type.__new__(cls,name,bases,update_attrs)

class Chinese(metaclass=Mymetaclass):
    country='China'
    tag='Legend of the Dragon' #龙的传人
    def walk(self):
        print('%s is walking' %self.name)


print(Chinese.__dict__)
'''
{'__module__': '__main__',
 'COUNTRY': 'China', 
 'TAG': 'Legend of the Dragon',
 'walk': <function Chinese.walk at 0x0000000001E7B950>,
 '__dict__': <attribute '__dict__' of 'Chinese' objects>,                                         
 '__weakref__': <attribute '__weakref__' of 'Chinese' objects>,
 '__doc__': None}
'''

练习二:在元类中控制自定义的类无需init方法

1.元类帮其完成创建对象,以及初始化操作;
  2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
  3.key作为用户自定义类产生对象的属性,且所有属性变成大写

class Mymetaclass(type):
    # def __new__(cls,name,bases,attrs):
    #     update_attrs={}
    #     for k,v in attrs.items():
    #         if not callable(v) and not k.startswith('__'):
    #             update_attrs[k.upper()]=v
    #         else:
    #             update_attrs[k]=v
    #     return type.__new__(cls,name,bases,update_attrs)

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError('must use keyword argument for key function')
        obj = object.__new__(self) #创建对象,self为类Foo

        for k,v in kwargs.items():
            obj.__dict__[k.upper()]=v
        return obj

class Chinese(metaclass=Mymetaclass):
    country='China'
    tag='Legend of the Dragon' #龙的传人
    def walk(self):
        print('%s is walking' %self.name)


p=Chinese(name='egon',age=18,sex='male')
print(p.__dict__)
Python元类详解 Python从设计之初就是一门面向对象的语言,它有一个重要的概念,即一切皆对象。Python与java的区别:Java虽然也是面向对象编程的语言,但是血统没有Python纯正。比如Java的八种基本数据类型之一int,在持久化的时候,就需要包装成Integer类对象。但是在python中,一切皆对象。数字、字符串、元组、列表、字典、函数、方法、类、模块等等都是对象,包括你的代码。MetaClass元类,本质也是一个类,但和普通类的用法不同,它可以对类内部的定义(包括类属性和类方法)进行动态的修改。 阅读详情

相关推荐

python 中的元类

本文详细而清晰地介绍了python 中元类的相关知识,metaclass 的用法,以及 with_metaclass

你不是叶秋的博客 1386

python3全栈开发- 元类metaclass(面试必考题)

一、知识储备 #exec:三个参数 #参数一:字符串形式的命令 #参数二:全局作用域(字典形式),如果不指定,默认为globals() #参数三:局部作用域(字典形式),如果不指定,默认为locals() exec的参数格式 #可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中 g={ 'x':...

195

conda环境的复制、备份操作

请确保将 source_env 替换为你要复制的现有环境的名称,并将 target_env 替换为你要创建的新环境的名称。要备份一个Conda虚拟环境,你需要将环境的配置信息和依赖包列表保存起来,以便在需要的时候能够重新创建相同的环境。要将现有的 conda 环境复制为其他环境,可以使用 conda create 命令并克隆已存在的环境。

Dollhan的博客 3772

python元类的使用_python中元类用法实例

本文实例讲述了python中元类用法,分享给大家供大家参考。具体方法分析如下:1.元类(metaclass)是用来创建类的类2.type(object):返回一个对象的类型,与object.__class__的值相同,type(name,bases,dict):创建一个新的type类型,name就是新class的name,值存到__name__属性中,bases是tuple类型,值会存到__bas...

weixin_30424461的博客 369

HCIP-Cloud Service DevOps Engineer V2.0 华为认证云服务 DevOps高级工程师 章节测试题+结课测试题(模拟考试题)汇总

本文为HCIP-Cloud Service DevOps Engineer V2.0 华为认证云服务DevOps高级工程师 在线课程中所有章节测试以及结课测试(HCIP-Cloud Service DevOps Engineer模拟考试)习题和答案

gaogao0305的博客 2267

无人机避障——卡内基梅隆大学(CMU)CERLAB 无人机自主框架复现

CMUCERLAB无人机自主框架是一个模块化的无人机自主导航系统,包含感知、测绘、规划和控制等组件。安装过程中遇到的主要问题包括:(1)cv_bridge路径未正确识别,需手动指定路径;(2)OpenCV版本冲突(4.2与4.6),导致动态导航节点崩溃。解决方案包括:完全卸载OpenCV4.2,重新编译安装OpenCV4.6,并修改相关CMakeLists文件指定版本。最终成功运行仿真环境,实现无人机在Gazebo和RViz中的自主避障导航功能。

weixin_45390670的博客 1646

Python自定义类的实现方式(元类)

一,使用函数实现 def upper_attr(class_name, class_parents, class_attr): new_attr = {} for name, value in class_attr.items(): if not name.startswith('__'): new_attr[name.upper()] = value # 将属性名转为大写后返回给创建的类 return type(class_name,

youcijibi的博客 1152

ios快捷指令进行钉钉打卡

首先 1、打开快捷指令 2、自动化 3、创建个人自动化-特定时间 4、添加操作-搜索“随机数” 5、最小值和最大值填充 6、添加操作-搜索“等待” 7、长按“1秒钟”,选择魔法变量,选择上一步的随机数 6、添加操作-搜索“钉钉” 7、选择钉钉-随便一个聊天窗口。 8、添加操作-搜索“等待”,这次将等待时间设为10秒 9、添加操作 “搜索天气” ,选择显示天气。 注意点: 1、此操作依赖于钉钉极速打卡,只是帮忙唤起钉钉。 2、保存自动化时有个运行前询问,务必关掉。 3、手机不能设

blaze_jack 5万+

python元类_Python元类

python元类Welcome to today’s tutorial on python metaclass. We all know that python is an object oriented programming language which means it binds datas with functionalities i.e. class. Before starting...

从零开始的教程世界 211

Halcon 深度学习实战:PCB 缺陷检测模型的 TensorRT/OpenVino 加速推理

本文介绍了如何利用TensorRT和OpenVino对Halcon深度学习模型进行加速优化,以提升PCB缺陷检测系统的实时性能。文章详细阐述了模型加速框架的选择策略(根据硬件选用TensorRT或OpenVino)、优化流程实施(包括混合精度优化和模型导出)以及加速后的推理实现。实验结果表明,优化后的模型体积缩小40%,推理速度提升2-5倍(GPU环境下从79ms降至38ms,CPU环境下从3804ms降至2152ms),同时保持检测精度。通过完整的代码示例展示了从模型加速到实际部署的全流程,为工业视觉场景

LIN943168247的博客 535

【数据集3】高分辨率统计降尺度日值数据集NEX-GDDP的介绍与下载方法

对NEX-GDDP数据集进行介绍和下载说明

WW、forever的博客 2393

封神级!268页Python核心知识笔记,从入门到精通看这一篇就够了

本文档一共26个章节,分别为:第 1 章 基本环境第 2 章 内置类型第 3 章 表达式第 4 章 函数第 5 章 迭代器第 6 章 模块第 7 章 类第 8 章 异常第 9 章 装饰器第 10 章 描述符第 11 章 元类第 12 章 字符串第 13 章 数据类型第 14 章 数学运算第 15 章 ⽂件与⺫录第 16 章 数据存储第 17 章 数据压缩第 18 章 格式解析第 19 章 数据加密第 20 章 操作系统。

2301_78094861的博客 535

Open Lovable 网站克隆AI工具超详细实战教程(含环境配置、排错与代码修改)

本教程面向有一定计算机基础的新手用户,提供一份全面、深入的 Open Lovable 使用指南。从开发环境搭建、API密钥获取、项目部署到网站克隆、代码下载、本地运行与二次开发,涵盖全流程细节与常见问题解决方案。通过本教程,新手可掌握如何利用AI驱动的Open Lovable工具,将任意目标网站智能复刻为结构清晰、可编辑的现代前端项目(React/Vite),实现快速原型开发与技术学习。

hy行者勇哥的博客 4962

【Python 元编程】元类入门指南✨

元类是Python中一种强大但复杂的工具。它们在正确使用时能够带来极大的灵活性和强大的功能,在大多数日常编程任务中,你可能不需要使用元类。只有在处理一些更复杂的面向对象设计问题时,才需要考虑使用元类。

苟日新,日日新,又日新!!! 1599

SAP FICO应付票据平台开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

SAP FICO应付票据平台开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

我好像病了的博客 379

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Python中的元类

Python中的元类 Python一切皆对象,所以类也是对象。 我们知道,对象是通过类实例化创建出来的。但我们创建类时并没有进行实例化操作,为什么类也是对象呢? 类既然是对象,类肯定是另外某个类的实例。这说明在我们使用class声明一个类的时候Python解释器为我们做了些什么。 一、元类介绍 通过一个类,可以创建无数个实例对象,类就相当于一个生产实例对象的机器,可以不断的生产出实例对象...

weixin_43790276的博客 3915

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

python——元类、元类实现orm

元类 1. 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这一点仍然成立: >>> class ObjectCreator(object): … pass … >>> my_object = ObjectCreator() >>> print(my_object) <__main_...

GC 6794

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Python 元类

元类是“类的类”,它用于定义类的行为。换句话说,元类是创建类的模板。在 Python 中,类本身也是对象。元类用于控制类的创建过程,比如类的属性、方法、继承关系等。

weixin_67459449的博客 1473

python中的元类

最近学习到了元类,在此记录其相关概念与应用,希望能够帮到对此有疑惑的人。

qq_75229677的博客 1315

[Python学习日记-70] 元类

在上一篇章当中我们已经了解了面向对象的各种内置函数了,本篇我们将讲述“元类”,它是 Python 面向对象编程的深层次知识,学会了元类可以做到很多神奇的姿势,这次就带大家一起来探讨一下什么是元类,我们应该如何定制自己的元类,我们应该怎么调用我们自己的元类。

JovaZou的成长之路 1210

Python 中的元类是什么

元类是创建类的“东西”。你定义类是为了创建对象,对吧?但我们了解到 Python 中的类也是对象。那么,元类就是创建这些对象的东西。你已经看到type这是因为type函数实际上是一个元类。type是 Python 在幕后用来创建所有类的元类。现在你可能会想,“为什么它是小写的,而不是Type?嗯,我想这是为了与str(创建字符串对象的类)和int保持一致。在 Python 中,一切,我是说一切,都是对象。这包括整数、字符串、函数和类。所有这些都是对象。那么,任何__class__的。

liluo0815481的博客 992

python的元类以及应用,元类实现ORM

使用ORM可以方便的进行关系型数据库库操作,减少开发负担。要实现ORM的重点,就是如何把类和实例与关系型数据库进行映射。python的元类,可以在拦截和修改类的创建,因此可以通过元类,在类的定义时,进行映射。回到最初的问题:ORM一定要用元类来实现吗?通过上述的内容可以得知,只要能够完成映射,就不一定需要用元类。后续会展示不使用元类实现的ORM。

weixin_68789096的博客 1015

Python基础:元类

通过上面的介绍,终于模模糊糊的带到元类这里来了。可是我们到现在还不知道元类是什么鬼东西。我们创建类的时候,大多数是为了创建类的实例对象。那么元类呢?元类就是用来创建类的。也可以换个理解方式就是:元类就是类的类。通过上面type()函数的介绍,我们知道可以通过type()实际上type()函数是一个元类。type()就是 Python 在背后用来创建所有类的元类。那么现在我们也可以猜到一下为什么type()函数是 type 而不是 Type呢?

在技术的广袤天地里,本博客如精准罗盘。剖析前沿科技,深掘代码奥秘,以精炼笔触,带您穿越复杂技术迷宫,速达知识彼岸。 887

Python的元类

有关于元类方面一些常用知识。

qq_38380338的博客 1148
上一篇: python入门学习笔记之内置方法(二)
下一篇: python入门学习笔记之领域模型
程序员_大白
博客等级 码龄5年 1万+粉丝 4001原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值