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
- Python中super()或object.__new__报TypeError: object.__new__() takes no arguments错误的解决方案
- python TypeError: object.__init__() takes no arguments错误
- python面向对象-理清object与type的关系
- Python 的 type 和 object 之间是怎么一种关系?
- Python 的 type 和 object 之间是怎么一种关系?
- python中 type object class之间的关系
- 【原创】Python 对象创建过程中元类, __new__, __call__, __init__ 的处理
- python面向对象-理清object与type的关系
- python面向对象-理清object与type的关系
- python面向对象-理清object与type的关系
- Python 的 type 和 object 之间是怎么一种关系?
- python错误:TypeError: 'module' object is not callable
- python 编译错误TypeError: 'builtin_function_or_method' object has no attribute '__getitem__'
- python中的__init__ 、__new__、__call__小结及使用
- Python: TypeError: 'int' object is not callable
- python报错 TypeError: object() takes no parameters
- python TypeError: 'int' object is not iterable
- python - 数据库 及 TypeError: 'zip' object is not subscriptable
- python错误: TypeError:'dict' object is not callable
- Python super(Todo,self).__init__() TypeError: super() argument 1 must be type, not classobj