元类

元类

什么是元类?

要知道什么是元类就必须要了解一个大前提:python中所有的都是对象

在知道这个前提下我们就可以知道类也是一个对象 Σ(⊙▽⊙"a

那么一个对象就会有一个类来负责创建它

我们就把创建 “类”(实际也是一个对象)的 “类” 叫做——元类

怎么找到元类呢?

我们可以使用 type 方法来打印对象的类型

那么我们是不是也可以用 type 来打印类的数据类型呢?

print(type(list))   # <class 'type'>
print(type(str))   # <class 'type'>
print(type(object))   # <class 'type'>

就连所有的类的基类都是object类都是由元类所创建的

发现所有的类都是由 type 创建的。img

??type??这不是经常用的一个内置方法吗?

怎么又变成了创建类的类了???

虽然我们看不到它的源码,但是它很知趣的给了我们大概的解释:

它可以传递一个参数或者传递三个参数:

  • 一个参数:对象的类型(来自百度翻译)
  • 三个参数:一个新对象(来自百度翻译)

原来它真的就是可以用来创建对象。孤陋寡闻,孤陋寡闻。

创建类的参数的含义

  • object_or_name :类名
  • bases : 继承的父类(元祖的形式传递)
  • dict :类的命名空间(所有的属性与方法)

使用type创建一个类

既然我们已经知道type怎么用了那么我们就用这个 “马良笔” 来手动的创建一个类

def set_name(self,name):
    self.name = name

def get_name(self):
    return self.name

# 手动创建一个类
Custom = type('Custom',(object,),{'set_name': set_name, 'get_name': get_name})
# 实例化Custom类
obj = Custom()
obj.set_name('gredae')
print(obj.get_name())   # gredae

个人感觉class会不会也是重写了__enter__和__exit__方法来实现一个类的信息获取,再使用exce函数将类的名称空间里的所有属性与方法给写成一个字典,这样类的名称,类继承的所有父类,与类的属性与方法就全部都有了,再在底层调用type来生成类。。

自定义一个元类

type 好像是用C语言写的。嗯~算了,从入门到入坟。。。

我们换一种思路吧!我们直接继承 type 然后对 type 的方法重写来实现自定义一个元类,嗯~可行性很高。

class Mytype(type):
    pass
Custom = type('Custom',(object,),{'set_name': set_name, 'get_name': get_name})
print(type(Custom))   # <class '__main__.Mytype'>

好了,我们实现了自定义元类,好像还没有重写它的方法。。

重写方法之前要知道实例化一个类经过了那些步骤

  • 前面我们说到类也是对象,是由 type 创建的,那么我们将类实例化的时候是这样的 list() 当我们这样实例化类的时候就会调用 type__call__ 方法
  • 而后在 __call__ 方法里面先使用 __new__ 创建一个空白的对象,什么都没有的对象。
  • 然后使用新创建的这个对象来调用该类的 __init__ 来初始化这个对象
  • 最后再返回该对象。这样才能实例化一个类。

虽然上面的步骤很多,但是实际实现起来也很多。嗯,没错。

我们来实现自定义元类:

class Mytype(type):
    def __call__(self, *args, **kwargs):
        obj = object.__new__(self)
        obj.__init__(*args, **kwargs)
        return obj

class Custom(metaclass=Mytype):
    def set_name(self, name):
        self.name = name

    def get_name(self):
        return self.name

f = Custom()
print(type(f))   # <class '__main__.Custom'>
print(type(Custom))   # <class '__main__.Mytype'>
f.set_name('gredae')
print(f.get_name())   # gredae

终于一个功能齐全的自定义元类完成了。。

属性查找

最后再来说下类的属性查找和对象的属性查找

  • 类:先从类本身中找 -> mro继承关系去父类中找 -> 去自己定义的元类中找 -> type中 -> 报错
  • 对象:先从对象自身找 -> 类中找 -> mro继承关系去父类中找 -> 报错
posted @ 2019-09-03 17:12  戈达尔  阅读(175)  评论(0编辑  收藏  举报