文章目录
前言
在面向对象编程中有个难点,元类
,本章总结下元类的定义和使用以及详细的对象
实例化过程
章节一、实例化对象
一句话描述: 元类的实例化对象是类对象
, 类的实例化对象是实例对象
1. __new__的参数
__new__(cls, *args, **kwargs)
在实例化对象时,Python解释器自动将该类当做第 一个参数传入cls, 然后其他参数则按照入参规则传入args
和kwargs
, 而后解释器又将__new__
的返回值及args
,kwargs
作为参数传入__init__
, 即:__new__
跟的参数除了cls其他由__init__
决定(元类的除外, 参考章节三)class A: def __new__(cls, *args, **kwargs): print(f'当前类 {cls} 参数 args {args}, kwargs {kwargs}') return super().__new__(cls) def __init__(self, *args, **kwargs): print(f'当前类 {self} 参数 args {args}, kwargs {kwargs}') >>> A(1, 2, 3, a=6) 当前类 <class '__main__.A'> 参数 args (1, 2, 3), kwargs {'a': 6} 当前实例 <__main__.A object at 0x0000000001DD4978> 参数 args (1, 2, 3), kwargs {'a': 6}
2. __new__的返回值
- __new__的返回值必须是
自己的实例
或者object.__new__(cls)
, 否则内部调用将会出现混乱, 用一个例子说明下类的创建及初始化过程 - 示例
class B(object): def __new__(cls, *args, **kwargs): print('------B __new__----------') return object.__new__(cls) def __init__(self): print('--------B 的 __init__-----------') class A(B): def __new__(cls, *args, **kwargs): instance = B.__new__(cls) return instance def __init__(self): super().__init__() print(f'__init__:: {self} A的 __init__') def __call__(self, *args, **kwargs): print('__call__:: A.__call__') >>> A()
3. 引自官网
- 调用来创建类cls的新实例。new()是一个静态方法(特殊大小写,所以不需要这样声明),它将实例被请求的类作为其第一个参数。剩下的参数是那些传递的参数
- 如果__new__()返回一个cls实例,则新实例的__init__()方法将像__init__(self[,…])一样被调用,其中self为新实例,其余参数与传递给__new__()的参数相同。
- 如果__new__()不返回cls的实例,则新实例的__init__()方法将不会被调用。
- new()主要用于允许不可变类型(如int、str或tuple)的子类自定义实例创建。在自定义元类中也通常重写它,以自定义类的创建。
4. __new__和__init__的区别
__new__(cls, [...])
负责对象的创建 返回值是: 实例化出来的实例, 实例对象创建完成后调用__init__(self, [...])
方法, 传入的第一个参数就是__new__
返回的实例对象,这一切的调用是有Python解释器自动完成的,总之,__new__
负责对象的创建,__init__
负责对象的一些初始化操作, 两个共同构成了类的构造器
。
5. 常用场景-单例模式
-
class A: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance
章节二、type
1. 是什么?
- 是实例化类的类, 即
元类
可以看到用法为:class type(object): """ type(object) -> the object's type type(name, bases, dict) -> a new type """ ... def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__ """ type(object) -> the object's type type(name, bases, dict) -> a new type # (copied from class doc) """ pass
type(object) -> the object’s type: 入参对象
, 返参对象类型
type(name, bases, dict) -> a new type: 入参分别为类的名称
,基类元组
,属性字典
, 返参为一个新的类
2. 作用
- 1.判断对象类型
>>> type(1) <type 'int'> >>>
- 2.动态创建类
以上的定义方式等同于def fun(self): print(f'the instance {self}, fun demo') ClassObj = type('ClassObj', (object, ), {"a": 1, "fun": fun}) >>> ClassObj().fun() the instance <__main__.ClassObj object at 0x7feb0e909850>, fun demo >>> ClassObj.__name__ 'ClassObj' >>>
class ClassObj(object): a = 1 def fun(self): print(f'the instance {self}, fun demo')
在Python解析器解析到class语句的时候会对语句后面的部分做type的实例化操作, 可以根据这个特性做一些定制化
的操作,如单例模式
, ``
章节三、metaclass(元类)
知道了type
的作用,那可以通过自定义元类
来实现用户自定义的操作
1. 自定义元类
- code
class Metaclass(type): def __new__(mcs, class_name, base_class, class_attr): assert isinstance(base_class, tuple) print(f'元类 {mcs}, 参数 class_name={class_name}; base_class={base_class}; class_attr={class_attr}') return type.__new__(mcs, class_name, base_class, class_attr) class A(object, metaclass=Metaclass): pass >>> 元类 <class '__main__.Metaclass'>, 参数 class_name=A; base_class=(<class 'object'>,); class_attr={'__module__': '__main__', '__qualname__': 'A'}
2. 元类使用 - 单例模式
- code
class MetaClass(type): def __call__(cls, *args, **kwargs): instance = getattr(cls, "instance", None) if instance is None: instance = super().__call__(*args, **kwargs) setattr(cls, "instance", instance) return instance class A(metaclass=MetaClass): def __init__(self, *args, **kwargs): print(f"args={args}, kwargs={kwargs}")