元类简介
- 元类(metaclass),元类是对类的概念的一种抽象定义,
type
是创建类的默认元类
- 创建类的时候,先调用元类的
__new__
方法,再调用元类的 __init__
方法,如果元类没有相应的方法,调用 type 的同名方法
- 创建类的实例的时候,先调用类的
__new__
方法,再调用类的 __init__
方法,如果类没有相应的方法,调用 object 的同名方法
- 当一个类继承自
type
时,这也就是一个元类,创建元类其实就是重写 type
中的各种方法的过程
1 2 3 4 5 6 7 8 9 10 11
| def get_name(self): print(self.name)
def init(self, name): self.name = name
User = type('User', (object, ), {'__init__': init, 'get_name': get_name})
user = User('王大锤') user.get_name()
|
元类 __new__
在定义元类的 __new__
方法时,通常需要传递以下几个参数
metacls
- 同 self
,代表元类自身
cls_name
- 要创建的类的类名
super_cls_tuple
- 新建的类需要继承的父类的元祖
args_dict
- 是一个字典,里面包含了类的方法和类属性,如 __module__
\ __doc__
等, 类的属性也会添加进来
通过自定义元类的 __new__
方法,可以实现以下特性
- 默认给类添加属性或方法
- 强制要求子类实现特定的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class ListMeta(type): def __new__(metacls, cls_name, super_cls_tuple, args_dict): args_dict['add'] = lambda self, value: self.append(value) return super().__new__(metacls, cls_name, super_cls_tuple, args_dict)
class List(list, metaclass=ListMeta): pass
if __name__ == '__main__': my_list = List() my_list.append(1) my_list.add(2) print(my_list)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class ListMeta(type): def __new__(cls_meta, cls_name, cls_super, args_dict): if 'add' not in args_dict: raise TypeError("Class must have add function") return super().__new__(cls_meta, cls_name, cls_super, args_dict)
class List(list, metaclass=ListMeta): def add(self, item): self.append(item)
if __name__ == '__main__': lst = List() lst.add(123)
|
元类 __init__
在定义元类的 __init__
方法时,通常需要以下参数
cls
- 进行创建的类本身(不是元类,是新建的类)
name
- 新建的类的类名
bases
- 新建的类所继承的类
namespace
- 新建的类的属性和方法
当调用 __init__
函数时,类已经被创建了,所以用该方法通常是进行对类的属性进行增删
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class ListMeta(type):
def __new__(metacls, cls_name, super_cls_tuple, args_dict): return super().__new__(metacls, cls_name, super_cls_tuple, args_dict) def __init__(cls, name, bases, namespace): if not hasattr(cls, "length"): cls.length = lambda cls: len(cls)
class List(list, metaclass=ListMeta): def add(self, item): self.append(item)
lst = List([1, 2]) lst.add(123) print(lst.length()) print(lst)
|
元类 __call__
元类中的 __call__
函数是在创建的类在尝试进行实例化的时候被调用的,所以可以通过该函数来对类进行实例化时做限制,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class NoInstanceMeta(type): def __call__(cls, *args, **kwargs): raise TypeError("Faild to Instance")
class NoInstance(metaclass=NoInstanceMeta): name = 'stolen'
@classmethod def hello(cls): print(f'Hello, {cls.name}')
print(NoInstance.name) NoInstance.hello() no_instance = NoInstance()
|
1 2 3 4 5 6 7 8 9 10
| class SingletonMeta(type):
def __init__(cls, *args, **kwargs): cls.__instance = None
def __call__(cls, *args, **kwargs): if cls.__instance is None: cls.__instance = super().__call__(*args, **kwargs) return cls.__instance
|