元类
exec
参数1:字串形式命令
参数2:全局作用域(字典形式),如果不指定默认就使用globals()
参数3:局部作用域(字典形式),如果不指定默认就使用locals()
g = {"x":1,"y":2} l = {} exec(''' global x,m x=10 m=100 z = 3''',g,l) # 引号中产生一个变量,变量放到局部作用域中 print(g) print(l)
引号中产生一个变量,变量放到局部作用域中
python中一切皆对象。
对象使用:
1、都可以被引用,x=obj
2、都可以当做函数的参数传入
3、都可以当做函数的返回值
4、都可以当做容器类的元素(列表、元组、字典、集合,可以装多种值)
元类
产生类的类称之为元类,默认用class定义的类,他们的元类是type
定义类的两种方式:
方式一:class
class Chinese(objext,metaclass = type): # Chinese = type(...) metaclass元类 country = "China" def __init__(self,name,age): self.name = name self.age = age def talk(self): print("%s is talking" %self.name)
方式二:type
定义类的三要素:类名、类的基类们。类的名称空间
类名(字符串):class_name = "Chinese"
继承(元组形式):class_bases = (object,)
类体(定义阶段类体代码立即执行)类的名称空间(字典形式):class_dic
# 类的名称空间的产生 class_body =''' country = "China" def __init__(self,name,age): self.name = name self.age = age def talk(self): print("%s is talking" %self.name) ''' class_dic = {} exec(class_body,globals(),class_dic) print(class_dic)
#实例化
Chinese = type(class_name,class_bases,class_dic) # 实例化元类,得到元类的对象(就是用class声明的类)
自定义元类,控制类的行为
class Foo: """注释""" pass print(Foo.__dict__)
#__doc__ 存放注释信息
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) 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)
自定义元类,控制实例化的行为
__call__
# __call__方法 调用对象会触发__call__,将对象本身连同参数一起传入该方法中。
__call__控制类的实例化行为
__init__控制类的创建行为
class Foo: def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) obj = Foo() obj(1,2,3,a=1,b=2,c=3) # obj.__call__(obj,1,2,3,a=1,b=2,c=3)
<__main__.Foo object at 0x000002C36C7F0358>
(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3
元类内部也应该有一个__call__方法,会在调用Foo时触发执行
Foo(1,2,x=1) # Foo.__call__(Foo,1,2,x=1)
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): print(self) # self= Chinese print(args) # args=('alex',) print(kwargs) # kwargs={'age': 18} 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("alex",age=18) # Chinese.__call__(Chinese,"alex",18)
<class '__main__.Chinese'>
('alex',)
{'age': 18}
控制类的实例化行为
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("alex",age=18) # print(self) # self= Chinese # print(args) # args=('alex',) # print(kwargs) # kwargs={'age': 18} # 第一步:创造一个空对象 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("alex",age=18) # Chinese.__call__(Chinese,"alex",18) print(obj.__dict__)
{'name': 'alex', 'age': 18}
自定义元类控制类的实例化行为的应用
单例模式 参数一样,不要再新生新的内存空间
实现方式1:
class MySQL: __instance = None 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() print(obj1 is obj2)
True
实现方式2:通过元类实现
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) self.__instance = None def __call__(self, *args, **kwargs): #控制类的实例化行为 # 第一步:创造一个空对象 if not self.__instance: obj = object.__new__(self) # 第二部:初始化obj self.__init__(self) self.__instance = obj # 第三部:返回obj return self.__instance class Mysql(object,metaclass=Mymeta): """自定义元类控制类的实例化行为的应用""" __instance = None 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() print(obj1 is obj2)
True