面向对象编程

python 是一门按照面向对象思维设计的一门编程语言,而理解面向对象的语言关键在于一句话,“一切皆对象”,函数是一个对象,一个实例是对象,一个类也是对象。如果对象被创建了,那么在这个程序管理的内存区域中,就会真实的存在一片区域去保存这个对象的信息。因此,我们在代码中定义一个函数,定义一个类,即使我们并没有调用这个函数或者去实例化这个类,在内存空间中,也已经存在了这个函数对象和类对象。例如下面的代码。

class A:def __init__(self, a, b):self.a = aself.b = b

代码执行后,内存中会创建一个类对象,且类对象上显式的绑定了__init__方法。

我们使用class A: pass这样的语句可以定义一个类,但是我们并没有在意它是如何被创建的,实际上这个语句的完整写法为

class A(metaclass=type):pass

这里metaclass=type 的意思是这个A类使用type类来创造,也就是使用type类作为他的元类,如果我们不声明,就默认使用type来创建这个类,而type也是一个类对象,这个类对象的功能,就是创建一个类,所以他与我们自己定义的普通的类又有所区别,所以有了metaclass,也就是元类的称呼。

何为元类

元类:简单的一句话就是创建类的类。首先元类也是一个类,,所以元类也是由另一个元类创建的,但是创建一个元类必须指定这个元类将继承哪个元类。下面看一些元类和普通类的区别。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class MetaclassA(type):   # 继承type类,并由type类创建,定义了一个元类passclass MetaclassB(MetaclassA):  # 继承MetaclassA,由type创建,定义了一个元类passclass MetaclassB(MetaclassA, metaclass=MetaclassB):  # 继承MetaclassA,由MetaclassBpass class C:        # 由type 类创建,继承object。是一个普通类passclass D(metaclass=MetaclassA):  # 由metaclassA 创建,继承object,是一个普通类pass

总结为两点

  • 类在创建时可以指定自己被哪个元类创建,使用metaclass参数指定一个元类即可,没指定默认为type元类
  • 定义的类是普通类还是元类,看他是直接继承自元类及其子类,还是继承自object及其子类。

元类的作用

元类的各类框架中使用较为广泛,由于自定义元类的参与,使得我们自己定义的类在创建时候,可以方便的进行一些自定义的初始化,完成我们想要的功能。在日常的编码中的一般很少使用元类,但是在阅读源码的过程中却常遇到,作者利用元类做一些非常精巧的设计去实现使用其他方法很难完成得功能。从下面的使用中体会元类的使用

元类的使用

默认情况下,类的创建都是交给 type元类 去创建,创建后的类有自己的默认的一些属性和方法,也有一部分从object类继承的属性和方法。如果我们想要在需要定义一个元类来实现类的自定义初始化,就必须继承自type或者及其子类。type类中默认创建类对象的方法为__new__(cls) 方法。我们可以重写这个方法。

class MetaClassA(type):def __new__(mcs, name, base, attrs):'''mcs,这个元类对象自己name:将要被创建的类的名字,下面的代码中 定义了一个 A 类,则这个name 为 "A" 这个字符串base: 被创建的类如果指定了需要继承某个类,base中将会纪录他所有的父类对象。attrs:被创建的类中定义的类属性和方法的字典,字典的key 为属性的变量名,value为对应的属性值'''# 查看这四个参数的值print(mcs, name, base, attrs)  # 类名,父类元组,类属性字典。'''输出的值msc: <class '__main__.Metaclass'>name: Abase:  (<class 'object'>,)attrs: {'__module__': '__main__',  '__qualname__': 'A', 'xxx': 1, 'x': <function A.<lambda> at 0x00000232DFF34620>, 'Meta': <class '__main__.A.Meta'>, '__init__': <function A.__init__ at 0x00000232DFF346A8>}'''# 查看参数值后,需要调用type类的new方法创建因为python 只提供了type元类来调用系统调用来申请内存空间,创建一个类对象并返回cls = type.__new__(mcs, name, base, attrs)# 返回值则是 A 这个类对象,我们可以使用dir查看类中的属性和方法,可以看到 上面attrs中的值,并新增了很多k-v对print(cls, dir(cls))return cls   # 必须使用 return 将这个类对象的返回,下面定义的class A 的 A 变量才能收到这个cls 对象,否则 A 的值为None, 即使使用了class A这个语法。# 我们使用MetaClassA 创建 类A
class A(object, metaclass=MetaclassA):# 为 A定义两个类属性xxx = 1yyy = lambda x: x + 1# 定义一个类, 这个类的也是A类的一个属性,可以通过A.Meta访问到这个类对象class Meta:x = []y = 1# 定义一个方法def __init__(self):self.a = 1 self.b = 2

通过上面的代码可以了解 一个类创建 的过程,在metaclassA的 ​__new__()​方法中,我们获取到了在 A 类中定义的所有类属性和方法,这些属性和方法都被收集到attrs 这个字典中,并交给type.__new__()方法用于创建类,所以想要操作类中的属性和方法,可以对attr字典进行想要的操作。例如我们为所有的类都添加一个方法。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def func():print("我是被 MetaClassA 创建的")class MetaClassA(type):def __new__(mcs, name, base, attrs):print(mcs, name, base, attrs)  # 类名,父类元组,类属性字典。attrs["show"] = func    # 将func 这个函数添加到A 的方法中,这样 A 类会有一个show方法,调用后会执行func函数。return type.__new__(mcs, name, base, attrs)

动态的创建类

动态的创建类 是指 直接通过 元类的方法来创建类,而不在使用 class 这个关键字来创建类对象。
使用关键字定义

class A:a = 1b = 2def show(self):pass

动态的创建

A = type.__new__(type, "A", (), {"a":1, "b":2, "show": lambda :pass})

这样的代码和上述的结果是相同的,或者还可以使用更直接的方法。我们知道普通类创建实例时候,可以ins = ClassName(*args)的方式创建一个实例对象 ins,同样,元类也可以如此创造一个类

A = type("A", (), {"a":1, "b":2, "show": lambda :pass})

对一个元类使用类似实例化的方法,得到了一个类对象。

综合一下:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Metaclass(type):def __new__(cls, class_name: str, bases: tuple, attrs: dict):print(1, cls)print(2, class_name)print(3, bases)return type.__new__(cls, class_name, bases, attrs)# 1. 创建一个类名为 A 的类,
class A(metaclass=Metaclass):a = 100# 2. 创建一个类名为 B 的类,使用 BClass变量接收
BClass = Metaclass.__new__(Meta, 'B', (),  {"a":100})  # 创建一个B类
print(BClass)# 3. 创建一个类名为 C 的类,,使用 CClass变量接收
CClass = Metaclass("C", (BClass, ), {"a": 100})        # 创建一个C类,并继承B类
print(CClass)

上面三个类的创建过程完全一致,处理类名不同和内存中的储存的地址不同,所拥有的属性和方法都是一样的。

元类的使用实例(django-orm中元类的简单使用原理)

Django的ORM中的Model类使用了元类来实现“表-类”,“实例-一条记录”,“实例属性-字段”的对应关系

class MetaModel(type):def __new__(mcs, class_name: str, bases: tuple, attrs: dict):# 收集所有的字段,并添加一些默认需要的属性,并提取设置为主键的 字段attrs.setdefault("db_table", class_name.lower())  # 设置表名for key, field in attrs:if isinstance(field, Field):if field.pk:          # 该字段被设置了主键,定义设置主键名字__primary__ = field.name or key   if not field.name:    # 没有自定义名字,使用属性名作为在field.name = keyreturn type.__new__(mcs, class_name, bases, attrs)# 字段对象,记录可字段的名字,类型,是否为null, 是否为主键等等元信息,和数据库中字段的元数据对应
class Field:def __init__(self, name=None, typ="varchar", null=None, primary_key=False):self.name = nameself.type = typself.null = nullself.pk = primary_keydef __repr__(self):return "<{}-{}-{}-{}>".format(self.name, self.type, self.null, self.pk)# 表对象,每一个类属性就是一个字段对象
class Person(metaclass=MetaModel):# 创建这个类时候,将会调用 MetaModel的new方法,这样定义的每个字段都会被 metaclass中attrs 收集并操作id = Field("id", primary_key=True)name = Field("name", )age = Field("age", null=False)

通过使用元类,在我们将这个Person类属性字典进行了操作,自动建立了一些属性信息,例如db_table将使用该名字作为数据库中表名,指定了属性__primary__作为主键。类似于Django中的做法,这里只是简单的演示元类的应用。

python元类简述相关推荐

  1. python 元类工厂模式_Python进阶丨如何创建你的第一个Python元类?

    摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...

  2. 如何创建你的第一个Python元类?

    Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一.通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类.本文介绍 ...

  3. Python进阶丨如何创建你的第一个Python元类?

    摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...

  4. python元类_Python元类

    python元类 Welcome to today's tutorial on python metaclass. We all know that python is an object orien ...

  5. python元类_Python基础:元类

    一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯面向对象 的.与那些仅在语法层面声称纯OO的编程语言(如Java)相比,Python的这种纯粹性更加深入骨髓. 在Python的世界 ...

  6. Python元类详解

    文章目录 Python元类详解 Python谜团 元类的本质 调用一个类时发生了什么 再探元类 自定义元类 彩蛋:跳过python解释器 Python元类详解 元类比99%的用户所担心的魔法要更深,如 ...

  7. 深入理解Python元类(原创)

    同样效果的代码: def __init__(cls,cls_name,cls_bases,cls_dict):type.__init__(cls,cls_name,cls_bases,cls_dict ...

  8. python元类深入理解

    1.python 中的类 在python中,类也是一个对象,只不过这个对象拥有生成实例的能力,我们一般使用class XXX来定义一个类,在python解释器执行到这个地方的时候会自动创建出这个对象, ...

  9. 深入理解 python 元类

    一.什么的元类 # 思考: # Python 中对象是由实例化类得来的,那么类又是怎么得到的呢? # 疑问: # python 中一切皆对象,那么类是否也是对象?如果是,那么它又是那个类实例化而来的呢 ...

最新文章

  1. 用 Python 画圣诞树的 N 种玩法
  2. 1322项!这所高校国自然基金立项再创新高 | 附各高校最新统计
  3. python的历史 常量 注释 基础数据类型等基本操作 和if 判断语句
  4. vue路由切换组件没有加载_vue-router 路由跳转后没有加载组件
  5. struts2实现拦截器的方法
  6. linux重置root密码
  7. freebsd从安装到想要的状态配置
  8. 怎么关闭或者卸载ivanti_电脑软件卸载不了怎么办,教您解决电脑软件无法卸载方法技巧...
  9. 单纯形表的matlab输出,自编MATLAB版单纯性算法 可以列出单纯形表以及其他相关数据...
  10. SQL Server编程(01)流程控制
  11. 心音与心电信号分析之一--6.26--心音信号检测系统软件设计
  12. Visual Studio 2005 提示“试图运行项目时出错:无法启动调试。绑定句柄无效”~[解决方案]...
  13. 面向集团客户云计算运营平台的市场情况及产品发展——之云计算运营平台方案(二)...
  14. 凸优化有关的数值线性代数知识 4分块消元与Schur补
  15. wsdl2java validate_使用cxf wsdl2java进行客户端证书身份验证
  16. python中的snip用法_简单说说SNIP
  17. u盘文件突然不见了怎么样才能恢复呢?
  18. 51nod 1423 最大“二货”【单调栈】
  19. ubuntu18.04鼠标正常使用,而键盘失灵
  20. 交换机的各种工作模式

热门文章

  1. MariaDB/MySql 服务消失无法启动
  2. 《代码整洁之道:程序员的职业素养》一一1.5 参考文献
  3. static在类中的定义,和enum的用法
  4. js常见问题之为什么点击弹出的i总是最后一个
  5. linux挂载新硬盘,开机自动挂载
  6. JDBC+Servlet+JSP整合开发之22.JSP简介
  7. 创建安全 Windows CE 设备(转)
  8. 程序员交流平台_「建议收藏」10个适合程序员逛的在线社区
  9. 自由自在意式手工冰淇淋,健康时尚的美味零食
  10. 【整理】SD交货拣配(Picking)处理