Python3基础教程:元类详解

枫铃3年前 (2021-10-03)Python228

1.引入

Python中一切皆对象,所谓对象就是由类创建出来,那么创建对象的类本身也是一个对象,也就是说创建对象的类本身也由别的什么类创建,这种创建类的类就叫元类.

2.元类是谁?

type函数就是元类,没错就是那个打印数据类型的函数,也就是说是type创建了类.

我们写一个类然后打印一下他的属性看看

In [4]: class MyClass(object): 
   ...:     pass 
   ...:                                                                                           

In [5]: type(MyClass)                                                                             
Out[5]: type

可以看到MyClass类的类型是type,用Python语言来描述这种关系就是:

MyClass = type()

3.type和object的区别

刚接触元类时很容易搞混这两者.区别如下

type是说有类的创建者

object是所有类的父类

怎么理解呢?记住以下几点就OK了(可能有点绕)

  • type和object不是同一层的东西
  • type是元类object是普通类
  • 元类的对象是普通类,普通类的对象就是普通对象
  • 继承自object的类包括object本身都是普通类
  • 继承自type的类都是元类
  • 普通类都是元类的对象
In [9]: type(object)                                                                              
Out[9]: type

那么是谁创建了type呢?这个问题留给你们自己去找答案,我相信有很多小伙伴已经猜到了.

4.通过type创建普通类

由type创建普通类的格式为

变量名 = type("类名", ("继承的类",), {"属性名":"属性值"})

第二个参数是元组类型

举个例子

In [11]: Myclass = type("ClassName", (object,), {"name": "kainhuck", "foo":"bar"})                

In [12]: Myclass                                                                                  
Out[12]: __main__.ClassName

可以看到Myclass不是真正的类名,真正的类名是ClassName.

创建一个名为ClassA,继承自object类,并带有属性name和方法printName的类,写法如下

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
In [15]: def printName(self): 
    ...:     print(self.name) 
    ...:                                                                                          

In [16]: ClassA = type("ClassA",(object,),{"name":"myName", "printName":printName})               

In [17]: a = ClassA()                                                                             

In [18]: a.printName()                                                                            
myName

5.创建自己的元类

前面已经有过提示,我们可以通过继承type来创建自己的元类

举个例子:

In [20]: class MetaClass(type): 
    ...:     pass 
    ...:                                                                                          

In [21]: ClassA = MetaClass("ClassA",(object,),{"name":"myName", "printName":printName})          

In [22]: a = ClassA()                                                                             

In [23]: a.printName()                                                                            
myName

这个例子中我只继承type没有增加任何新的功能

我们知道创建一个对象的功能由__new__函数实现,下面我们通过修改__new__函数来创建一个必须含有printName方法的类.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
In [30]: class MyMetaClass(type): 
    ...:     def __new__(cls, name, bases, attrs): 
    ...:         func = attrs.get("printName", None) 
    ...:         if not callable(func): 
    ...:             raise NotImplementedError("必须创建一个名为 printName 的函数") 
    ...:         return type.__new__(cls, name, bases, attrs) 
    ...:          
    ...:                                                                                          

In [31]: ClassA = MyMetaClass("ClassA",(object,),{"name":"myName", "printName":"not callable"})   
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-31-772aa102a27f> in <module>
----> 1 ClassA = MyMetaClass("ClassA",(object,),{"name":"myName", "printName":"not callable"})

<ipython-input-30-c2ffcc442a77> in __new__(cls, name, bases, attrs)
      3         func = attrs.get("printName", None)
      4         if not callable(func):
----> 5             raise NotImplementedError("必须创建一个名为 printName 的函数")
      6         return type.__new__(cls, name, bases, attrs)
      7 

NotImplementedError: 必须创建一个名为 printName 的函数

In [32]: ClassA = MyMetaClass("ClassA",(object,),{"name":"myName", "printName":printName})        

In [33]:  

可以看到如果我们定义的类没有创建printName函数就会报错.

6.类工厂

所谓类工厂就是生产类的地方,我们可以设计一个函数,使该函数可以通过参数来返回不同的类.

男人和女人都是人,但是不同性别的人剪头发的时间不一样.我们就可以定义一个类工厂来按需求产生不同的类.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def Person(sex):
    def manCut(self):
        print("我是男人,我剪头发很快")

    def womanCut(self):
        print("我是女人,我剪头发很慢")

    if sex == "man":
        return type("man", (object,), {"hairCut": manCut})
    elif sex == "woman":
        return type("woman", (object,), {"hairCut": womanCut})
    else:
        print("Error")

Man = Person("man")
Woman = Person("woman")

lilei = Man()
hanmeimei = Woman()

输出:

我是男人,我剪头发很快
我是女人,我剪头发很慢

相关文章

利用python同步windows和linux文件

写python脚本的初衷,每次在windows编辑完文件后,想同步到linux上去,只能够登录服务器,...

爬虫基本原理

爬虫基本原理 一、爬虫是什么? 百度百科和维基百科对网络爬虫的定义:简单来说爬虫就是抓取目标网站内容的工具,一般是根据定义的行...

Django 函数和方法的区别

函数和方法的区别 1、函数要手动传self,方法不用传 2、如果是一个函数,用类名去调用,如果是一个方法...

Django 知识补漏单例模式

单例模式:(说白了就是)创建一个类的实例。在 Python 中,我们可以用多种方法来实现单例模式&#x...

Django基础知识MTV

Django简介 Django是使用Python编写的一个开源Web框架。可以用它来快速搭建一个高性能的网站。 Django也是一个MVC框架。但是在Dj...

Python mysql 索引原理与慢查询优化

一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。