元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
exec
# 可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中g = {'x': 1,'y': 2}l = {}exec('''global x,zx=100z=200m=300''', g, l)print(g.get('y')) # {'x': 100, 'y': 2,'z':200,......}print(l) # {'m': 300}
产生类的类称之为元类,默认所以用class定义的类,他们的元类是type
# 类也是对象,Foo=type(....)class Foo:passobj = Foo()print(type(obj)) # <class '__main__.Foo'>print(type(Foo)) # <class 'type'>
创建类的两种方式
# 方式一:classclass Chinese: # Chinese=type(...)country = 'China'def __init__(self, namem, age):self.name = namemself.age = agedef talk(self):print('%s is talking' % self.name)# print(Chinese)obj = Chinese('ecithy', 18)print(obj, obj.name, obj.age)
# 方式二:type# 定义类的三要素:类名,类的基类们,类的名称空间class_name = 'Chinese'class_bases = (object,)class_body = """country='China'def __init__(self,namem,age):self.name=namemself.age=agedef talk(self):print('%s is talking' %self.name)"""class_dic = {}exec(class_body, globals(), class_dic)# print(class_dic)Chinese1 = type(class_name, class_bases, class_dic)# print(Chinese1)obj1 = Chinese1('egon', 18)print(obj1, obj1.name, obj1.age)
元类控制类
class Mymeta(type):def __init__(self, class_name, class_bases, class_dic):if not class_name.istitle():raise TypeError('类名的首字母必须大写')if '__doc__' not in class_dic or not class_dic['__doc__'].strip():raise TypeError('必须有注释,且注释不能为空')super().__init__(class_name, class_bases, class_dic)class Chinese(object, metaclass=Mymeta): 默认 metaclass=type'''中文人的类'''country = 'China'def __init__(self, name, age):self.name = nameself.age = agedef talk(self):print('%s is talking' % self.name)people = Chinese('ecithy', 18)print(people.name)
元类控制类的实例化
语法
class Mymeta(type):def __init__(self, class_name, class_bases, class_dic):if not class_name.istitle():raise TypeError('类名的首字母必须大写')if '__doc__' not in class_dic or not class_dic['__doc__'].strip():raise TypeError('必须有注释,且注释不能为空')super(Mymeta, self).__init__(class_name, class_bases, class_dic)def __call__(self, *args, **kwargs): # obj=Chinese('ecithy',age=18)# 第一件事:先造一个空对象objobj = object.__new__(self)# 第二件事:初始化objself.__init__(obj, *args, **kwargs)# 第三件事:返回objreturn objclass Chinese(object, metaclass=Mymeta):'''中国人的类'''country = 'China'def __init__(self, name, age):self.name = nameself.age = agedef talk(self):print('%s is talking' % self.name)obj = Chinese('ecithy', age=18) # Chinese.__call__(Chinese,'ecithy',18)
应用
单例模式
# 实现方式一:class MySQL:__instance = None # __instance=obj1def __init__(self):self.host = '127.0.0.1'self.port = 3306@classmethoddef singleton(cls):if not cls.__instance:obj = cls()cls.__instance = objreturn cls.__instancedef conn(self):passdef execute(self):passobj1 = MySQL.singleton()obj2 = MySQL.singleton()obj3 = MySQL.singleton()print(obj1 is obj3) # True
# 实现方式二:元类的方式class Mymeta(type):def __init__(self, class_name, class_bases, class_dic):if not class_name.istitle():raise TypeError('类名的首字母必须大写')if '__doc__' not in class_dic or not class_dic['__doc__'].strip():raise TypeError('必须有注释,且注释不能为空')super().__init__(class_name, class_bases, class_dic)self.__instance = Nonedef __call__(self, *args, **kwargs): # obj=Chinese('egon',age=18)if not self.__instance:obj = object.__new__(self)self.__init__(obj)self.__instance = objreturn self.__instanceclass Mysql(object, metaclass=Mymeta):'''mysql xxx'''def __init__(self):self.host = '127.0.0.1'self.port = 3306def conn(self):passdef execute(self):passobj1 = Mysql()obj2 = Mysql()obj3 = Mysql()print(obj1 is obj2 is obj3) # True
