python--type,object,元类,__new__,__init__关系

上篇文章中通过代码方式,重点讲解了:

  1.__new__和__init__之间的关系,前者是用来创建类实例,后者用来初始化类实例,它两配合使用,才完整生成一个类实例。
  2.object和type之间的关系,前者负责继承这块工作,后者负责类型定义这块工作。即所有的对象都起源于object,所有的对象最终都是type这个类型。

本文将重点介绍元类和元类的创建。

1.什么是元类

元类是创建类的类。如何理解这句话,先看以下代码:

class B():
    pass
b=B()
print(b.__class__)
print(B.__class__)
print(object.__class__)
#打印情况:
<class '__main__.B'>
<class 'type'>
<class 'type'>

上述代码中b是由类B构建的,因此b的类型(通过__class__属性查看)是<class ‘main.B’>,而后面B和object的类型都是type,同理,这说明B和object都是由type这个类创建的,即type可以用来创建类。
能够创建类的类,我们称作元类,type就是最原始的一个元类。

2.type如何创建类

首先声明:type在python中有两个身份:
1.type当做函数用,同__class__属性作用相同,返回对象的类型
2.type当做类用,是元类,用于创建其它的类。

下面是当做类用。
语法:

type(类名称字符串,类继承的元组,类的属性/函数字典)

三个的参数含义和类型都在上面规定了。下面代码用type类创建了一个类A,并为类A创建了一个name属性和一个show函数(注意不是shows函数,尽管定义的时候是shows)

def shows(self,name):
    print(name)
#用type类创建类A
A=type("A",(object,),{'name':"bob",'show':shows})
aa=A()
print(aa.name)
aa.show("wangwu")

##输出结果
bob
wangwu
3.自定义元类

默认情况下,所有类都是由type元类创建,当然也可以自定义元类,这样该类的__class__属性就不是type了,而是该自定义元类。
语法:自定义元类必须要显示继承于type类。

class XXMetaClass(type):
	pass
4.设置类的元类为自定义元类
class XXClass(object,metaclass=XXMetaClass):
	pass
5.实例演练

下面代码中定义了一个元类TMetaclass,和三个普通类,且这三个普通类都是通过该元类生成的。由下面的打印结果可知,元类的__new__函数返回的值正是各个类。也就是说,在元类中是通过__new__函数生成类的。

class TMetaclass(type):
    def __new__(cls, name, bases, attrs):
        print("__new__参数:",cls, name, bases, attrs,'\n')
        
        print("__new__返回类型: ",type.__new__(cls, name, bases, attrs),'\n')
        return type.__new__(cls, name, bases, attrs)#生成相应的类,并返回

class Test1(dict,metaclass=TMetaclass):
    def __init__(self, **kw):
       super(T, self).__init__(**kw)   
    def p(self):
        print("ppp")
    pass

class Test2(Test1):
    pass

class Test3(Test2):
    pass
    
#结果打印:
__new__参数: <class '__main__.TMetaclass'> Test1 (<class 'dict'>,) {'__module__': '__main__', '__qualname__': 'Test1', '__init__': <function Test1.__init__ at 0x000002F08653E8C8>, 'p': <function Test1.p at 0x000002F08653E7B8>, '__classcell__': <cell at 0x000002F0864BA1C8: empty>} 

__new__返回类型:  <class '__main__.Test1'> 

__new__参数: <class '__main__.TMetaclass'> Test2 (<class '__main__.Test1'>,) {'__module__': '__main__', '__qualname__': 'Test2'} 

__new__返回类型:  <class '__main__.Test2'> 

__new__参数: <class '__main__.TMetaclass'> Test3 (<class '__main__.Test2'>,) {'__module__': '__main__', '__qualname__': 'Test3'} 

__new__返回类型:  <class '__main__.Test3'> 
6.类实例的生成过程

分为两个阶段:
1.类的生成:由元类生成;
2.实例的生成:由上述生成的类接着生成。

具体描述:

结合上一篇文章中,我们总结出生成一个类实例的全部过程:
1.类首先查找内部__metaclass__属性是否被自定义元类赋值,若赋值则准备用该自定义元类生成类,否则用type作为元类生成类;
2.解释器调用该元类的__new__函数(该函数为静态函数),并将要实例化的类中定义的各种属性传递给该函数固定的四个参数:其中cls是该元类本身,name是要被实例化的类的类名,bases是该类父类组成的元组,attrs则是该类{属性名:属性值,函数名:函数对象}组成的字典。
3.最终通过type类生成该类,并返回。
4.该类生成后,调用类中的__new__函数(该函数是静态函数)创建该类的实例,并返回该实例;
5.该实例接着调用它的__init__函数初始化实例,这样一个完整的实例就被生成出来了。

7.自定义元类的核心

由于是元类构建了类,因此若要更改某些固定类(str,int等)的用法,就必须在元类中做文章了。而元类的核心是__new__函数,自然在该函数内做文章。比如可以通过atrris字典为元类添加新的属性和函数,或改变以往的属性或函数等。这样的改变会传播到所有用该元类创建的类中。

总结:
__new__函数:
1.在元类中该函数用来构建类本身;
2.在类中,该函数用来构建类实例;

7.类函数调用方式
def A():
	def show(self,name):
		print(name)
a=A()
#我们的调用方式:
a.show("hello")
#实际解释器的调用方式,这个a实例填充了self这个参数的位置
A.show(a,"hello")
8.总结
class B(type):
    def __new__(cls, name, bases, attrs):  # 创建A的类对象
        print(cls)
        print(name)
        print(bases)
        print(attrs)
        print(type.__new__(cls, name, bases, attrs))
        return type.__new__(cls, name, bases, attrs)  # 返回由type创建A的类对象[会为A的类对象开辟相应的内存空间,用于通过A.__init__存储A的类对象的信息]


class A(object, metaclass=B):
    def __new__(cls, name, age):  # 创建的A的实例对象
        print("="*30)
        print("__new__")
        print(name, age)
        print(cls)
        print(object)
        print(object.__new__(cls))
        return object.__new__(cls)  # 返回创建的A的实例对象[会为A的实例对象开辟相应的内存空间]

    def __init__(self, name, age):  # 初始化A的实例对象[将A相应的属性信息存入锁开辟的空间中]
        print("=" * 30)
        print("__init__")
        print(name, age)
        print(self)
        self.name = name
        self.age = age


a = A("LiMing", 25)
print("=" * 30)
print("__main__")
print(a.name, a.age)


"""
执行结果:
<class '__main__.B'>
A
(<class 'object'>,)
{'__module__': '__main__', '__qualname__': 'A', '__new__': <function A.__new__ at 0x000001DB9D95EBF8>, '__init__': <function A.__init__ at 0x000001DB9D95EC80>}
<class '__main__.A'>
==============================
__new__
LiMing 25
<class '__main__.A'>
<class 'object'>
<__main__.A object at 0x000001DB9C92EBA8>
==============================
__init__
LiMing 25
<__main__.A object at 0x000001DB9C92EBA8>
==============================
__main__
LiMing 25

Process finished with exit code 0
"""

在这里插入图片描述
[参考博客]https://blog.csdn.net/qq_27056805/article/details/86554961
     https://blog.csdn.net/qq_27056805/article/details/86554961

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值