在Python中, 一切皆对象, 对象是类的实例化。那么类又是由什么实例化得到的呢?
元类的介绍
class People(object): def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s:%s' % (self.name, self.age))
obj = People('featherwit', 18) print(type(obj)) # <class 'People'> print(type(People)) # <class 'type'>
如果一切皆为对象,那么类本质也是一个对象,既然所有的对象都是调用类得到的,那么必然也是调用了一个类得到的,这个类称为元类。
所以调用关系为:
class关键字创建类的流程
我们用class关键字定义的所有的类以及内置的类都是由元类type实例化得到的
class关键字创建类的流程主要步骤为:
1. 拿到类名: class_name = "People" 2. 拿到基类: class_bases = (object, ) 3. 执行类体代码拿到类的名称空间: class_dic = {...} 4. 调用元类: People = type(class_name, class_bases, class_dic)
exec的用法:
exec:三个参数
参数一:包含一系列python代码的字符串
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
#可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
自定义元类控制类的创建
一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类 pass class People(metaclass=Mymeta): def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s:%s' % (self.name, self.age))
自定义元类可以控制类的产生过程,类的产生过程其实就是元类的调用过程,即
People = Mymeta(People, (object, ), {...}) # 步骤: # 1. 先造一个空对象 -> People, 调用类内的__new__方法 # 2. 调用Mymeta这个类内的__init__方法, 完成初始化操作 # 3. 返回初始化好的对象 -> 调用元类的__call__方法
class Mymeta(type): # 只有继承了type的类才是元类 def __init__(self, class_name, class_bases, class_dic): # print(self) # <class '__main__.People'> # print(class_name) # People # print(class_bases) # () # print(class_dic) # {'__module__': '__main__', '__qualname__': 'People', '__init__': <function People.__init__ at 0x7fe8f96bfe60>, 'say': <function People.say at 0x7fe8f96bfef0>} if not class_name.istitle(): raise NameError('类名的首字母必须大写') def __new__(cls, *args, **kwargs): # 造Mymeta的对象 # return type.__new__(cls, *args, **kwargs) return super().__new__(cls, *args, **kwargs)
自定义元类控制类的调用
class Foo: def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) obj=Foo() #1、要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法,该方法会在调用对象时自动触发 #2、调用obj的返回值就是__call__方法的返回值 res=obj(1,2,3,x=1,y=2)
调用一个对象,就是触发对象所在类中的__call__方法的执行,如果把类也当做一个对象,那么类这个对象的类中也必然存在一个__call__方法
# 如果想让一个对象可以加括号调用, 需要在该对象的类中添加一个方法__call__ class Mymeta(type): def __call__(self, *args, **kwargs): # 1. Mymeta.__call__函数内会先调用People内的__new__ people_obj = self.__new__(self) # 2. Mymeta.__call__函数会调用People内的__init__ self.__init__(people_obj, *args, **kwargs) # 3. Mymeta.__call__函数内会返回一个初始化好的对象 return people_obj class People(metaclass=Mymeta): def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s:%s' % (self.name, self.age)) def __new__(cls, *args, **kwargs): # 产生真正的对象 return object.__new__(cls)
默认的, 产生类的时候会做三件事情: # People = Mymeta(People, (object, ), {...}) -> type.__call__ # 1. type.__call__函数内会先调用Mymeta内的__new__ # 2. type.__call__函数会调用Mymeta内的__init__ # 3. type.__call__函数内会返回一个初始化好的对象 默认的, 调用类的时候会做三件事情 # obj = People('featherwit', 18) -> Mymeta.__call__() # 1. Mymeta.__call__函数内会先调用People内的__new__ # 2. Mymeta.__call__函数会调用People内的__init__ # 3. Mymeta.__call__函数内会返回一个初始化好的对象
元类的使用案例
实现单例模式
# 1. __new__()方法实现单例 class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls,"_instance"): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # 2. 元类实现单例 class Singleton(type): def __init__(self, *args, **kwargs): self.__instance = None super(Singleton,self).__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self.__instance is None: self.__instance = super(Singleton,self).__call__(*args, **kwargs) return self.__instance class Foo(metaclass=Singleton): pass