理解Python中的元类

1.引入

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

2.元类是谁?

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

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

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

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

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

MyClass = type()

3.typeobject的区别

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

type是说有类的创建者

object是所有类的父类

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

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

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

3.通过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的类,写法如下

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

4.创建自己的元类

前面已经有过提示,我们可以通过继承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方法的类.

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函数就会报错.

5.类工厂

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

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

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()

out:

我是男人,我剪头发很快
我是女人,我剪头发很慢
posted @ 2019-07-14 16:43  KainHuck  阅读(519)  评论(2编辑  收藏  举报