元类

元类

什么是元类?

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

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

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

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

怎么找到元类呢?

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

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

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

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

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

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

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

%E5%85%83%E7%B1%BB-type.png

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

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

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

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

创建类的参数的含义
  • 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来生成类。。

timg?image&quality=80&size=b9999_10000&sec=1567507105840&di=9592e7b3920520bde4eb0ebbf882473f&imgtype=0&src=http%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2FV5s1oDoXibbN3h1h7lzek91OFjJ7Wx2icSQ85k1glgCvibX2dfMeMY0hib0mehIH7ZoYjWVrt2WEEmEDkyJsfnficeA%2F640%3Fwx_fmt%3Djpeg

自定义一个元类

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

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

timg?image&quality=80&size=b9999_10000&sec=1567511580987&di=5f22407bc09d99b64b6a53fdc47f6cbd&imgtype=jpg&src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20161102%2Ff307c1632d2a4891b8fd5942ada78546.jpg

属性查找

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

  • 类:先从类本身中找 -> mro继承关系去父类中找 -> 去自己定义的元类中找 -> type中 -> 报错
  • 对象:先从对象自身找 -> 类中找 -> mro继承关系去父类中找 -> 报错

转载于:https://www.cnblogs.com/Gredae/p/11454220.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值