元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
exec
# 可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
g = {
'x': 1,
'y': 2
}
l = {}
exec('''
global x,z
x=100
z=200
m=300
''', g, l)
print(g.get('y')) # {'x': 100, 'y': 2,'z':200,......}
print(l) # {'m': 300}
产生类的类称之为元类,默认所以用class定义的类,他们的元类是type
# 类也是对象,Foo=type(....)
class Foo:
pass
obj = Foo()
print(type(obj)) # <class '__main__.Foo'>
print(type(Foo)) # <class 'type'>
创建类的两种方式
# 方式一:class
class Chinese: # Chinese=type(...)
country = 'China'
def __init__(self, namem, age):
self.name = namem
self.age = age
def 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=namem
self.age=age
def 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 = name
self.age = age
def 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)
# 第一件事:先造一个空对象obj
obj = object.__new__(self)
# 第二件事:初始化obj
self.__init__(obj, *args, **kwargs)
# 第三件事:返回obj
return obj
class Chinese(object, metaclass=Mymeta):
'''
中国人的类
'''
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
obj = Chinese('ecithy', age=18) # Chinese.__call__(Chinese,'ecithy',18)
应用
单例模式
# 实现方式一:
class MySQL:
__instance = None # __instance=obj1
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
@classmethod
def singleton(cls):
if not cls.__instance:
obj = cls()
cls.__instance = obj
return cls.__instance
def conn(self):
pass
def execute(self):
pass
obj1 = 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 = None
def __call__(self, *args, **kwargs): # obj=Chinese('egon',age=18)
if not self.__instance:
obj = object.__new__(self)
self.__init__(obj)
self.__instance = obj
return self.__instance
class Mysql(object, metaclass=Mymeta):
'''
mysql xxx
'''
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
def conn(self):
pass
def execute(self):
pass
obj1 = Mysql()
obj2 = Mysql()
obj3 = Mysql()
print(obj1 is obj2 is obj3) # True