您的位置:首页 > 编程语言 > Python开发

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

2019-10-24 10:30 411 查看
原文链接:https://www.geek-share.com/detail/2727262091.html

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

  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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: