第五章-面向对象-1.元类介绍/2.自定义元类控制类的行为/3.控制类的实例化行为/4.控制类的实例化行为的应用
1.元类介绍
1.储备知识exec()
参数1;字符串形式得命令
参数2.全局作用域(字典形式),如果不指定默认就使用globals()
参数3.局部作用域(字典形式),如果不指定默认就使用locals()
2.python 一切皆对象 ,对象可以怎么用?
2.1. 都可以被引用 x=obj
2.2. 都可以当作函数得参数传入
2.3. 都可以当作函数得返回值
2.4. 都可以当作容器类得元素 li=[func,time]
# 类也是对象,Foo=type() 类是属于type() 类
3.什么叫元类
类得类就叫元类 type type(Foo) == <class 'type'>
产生类得类称之为元类,默认所有用class定义得类,他们得元类是type
元类(type) --> 实例化 --> 类(class)--> 实例化 --> 对象
4.定义类得两种方式:
4.1 class 关键字得方式 class Chinese:
4.2 type 元类 定义类得三要素:类名,类的基类们,类得名称空间
Chinese1=type(class_name,class_bases,class_dic)
1 # print(globals()) 2 # g = { 3 # 'x':1, 4 # 'y':2 5 # } 6 # 7 # l = {} 8 9 # exec当做一个函数 10 # exec(""" 11 # global x,m 12 # x = 10 13 # m = 100 14 # 15 # z = 3 16 # """,g,l) 17 # print(g) 18 # print(l) 19 #------------------------------------------------------------- 20 # 类也是对象,Foo = type(...) 21 # class Foo: 22 # pass 23 # 24 # obj = Foo() 25 # print(type(obj),type(Foo)) 26 # # <class '__main__.Foo'> <class 'type'> 27 28 29 # 产生类的类称之为元类,默认所有用class定义的类,他们的元类是type 30 31 #-------------------------------------------------------------- 32 # 定义类的两种方式: 33 # 方式一:class 34 35 class Chinese: # Chinese = type(...) # Chinese类就是调用了一个type类实例化得到的 36 country = 'China' 37 38 def __init__(self,name,age): 39 self.name = name 40 self.age = age 41 42 def talk(self): 43 print('%s is talking ' % self.name) 44 45 # print(Chinese) 46 obj = Chinese('egon',18) 47 print(obj,obj.name,obj.age) 48 49 # 方式二:type 50 # 类定义三要素: 51 # 1.类名: 52 class_name = 'Chinese' 53 54 # 2.继承,类的基类们: 55 class_bases = (object,) 56 57 # 3.名称空间: 58 class_body = """ 59 country = 'China' 60 61 def __init__(self,name,age): 62 self.name = name 63 self.age = age 64 65 def talk(self): 66 print('%s is talking ' % self.name) 67 """ 68 class_dic = {} 69 exec(class_body,globals(),class_dic) 70 # print(class_dic) 71 72 # 实例化元类得到一个元类的对象也就是用class 声名的一个类 73 Chinese1 = type(class_name,class_bases,class_dic) 74 # print(Chinese1) 75 obj1 = Chinese1('egon',18) 76 print(obj1,obj1.name,obj1.age)
2.自定义元类控制类的行为
自定义元类 来控制 类的行为 控制类的创建行为
1 class Mymeta(type): 2 def __init__(self,class_name,class_bases,class_dic): 3 # print(class_name) 4 # print(class_bases) 5 # print(class_dic) 6 if not class_name.istitle(): 7 raise TypeError('类名的首字母必须为大写') 8 9 if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): 10 raise TypeError('必须有注释,且注释不能为空') 11 super(Mymeta,self).__init__(class_name,class_bases,class_dic) 12 13 class Chinese(object,metaclass=Mymeta): 14 '''1''' 15 country = 'China' 16 17 def __init__(self,name,age): 18 self.name = name 19 self.age = age 20 21 def talk(self): 22 print('%s is talking ' % self.name) 23 24 # Chinese = Mymeta(class_name,class_bases,class_dic) 25 26 27 # raise TypeError('类型错误!') 28 29 # class Foo: 30 # pass 31 # print(Foo.__dict__)
3.控制类的实例化行为
知识储备 __call__方法
obj(1,2,3,a=1,b=2,c=3) # 对象在调用时 会触发 __call__
------------------------------------
#生成对象步骤 --》 #1.先造空对象 2.初始化 3.返回值
def __call__(self, *args, **kwargs): 在元类的__call__()方法中实现
# 1.先造一个空对象
obj=object.__new__(self)
# 2.初始化obj
self.__init__(obj,*args,**kwargs)
# 3.返回obj
return obj
总结:元类
__init__ 控制类的创建
__call__ 控制类的实例化
1 # 如果希望对象可调用,可以在对象的类中写一个__call__方法,调用的时候触发该方法 2 # class Foo: 3 # def __call__(self, *args, **kwargs): 4 # print(self) 5 # print(args) 6 # print(kwargs) 7 # 8 # obj = Foo() 9 # obj(1,2,3,a=1,b=2,c=3) # obj.__call__(obj,1,2,3,a=1,b=2,c=3) 10 # 11 # # 元类内部也应该有一个__call__方法,会在调用Foo时触发执行 12 # # Foo(1,2,x=1) # Foo.__call__(Foo,1,2,x=1) 13 14 15 class Mymeta(type): 16 def __init__(self,class_name,class_bases,class_dic): 17 if not class_name.istitle(): 18 raise TypeError('类名的首字母必须为大写') 19 20 if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): 21 raise TypeError('必须有注释,且注释不能为空') 22 super(Mymeta,self).__init__(class_name,class_bases,class_dic) 23 24 def __call__(self, *args, **kwargs): # obj = Chinese('egon',18) 25 # print('=====>') 26 # print(self) # self = Chinese 27 # print(args) # args = ('egon', 18) 28 # print(kwargs) # kwargs = {} 29 # 第一件事:先造一个空对象obj 30 obj = object.__new__(self) 31 # 第二件事:初始化obj 32 self.__init__(obj,*args,**kwargs) 33 # 第三件事:返回obj 34 return obj 35 class Chinese(object,metaclass=Mymeta): 36 '''1''' 37 country = 'China' 38 39 def __init__(self,name,age): 40 self.name = name 41 self.age = age 42 43 def talk(self): 44 print('%s is talking ' % self.name) 45 46 obj = Chinese('egon',18) # Chinese.__call__(Chinese,'egon',18) 47 print(obj.__dict__)
4.自定义元类控制类的实例化行为的应用
单例模式: 对象的参数都一样 实质就是一个对象 不要在申请新的内容空间 直接使用一个 就是单例模式
eg: 单例模式对id的应用 obj1 和 obj2 公用一块内存 “优化策略”
>>> obj1=int(1)
>>> obj2=int(1)
>>> obj1 is obj2
True
>>> id(obj1)
1897295328
>>> id(obj2)
1897295328
--------------------------------
自己定义的类 对象内部的特征如果是一样的就公用一块内存 用单例模式呢:
实现单例模式 是一种 优化策略 多个对象公用一块内存
__instance=None #__instance=obj1
def singleton(cls):
print(obj1 is obj2)
-------------------------------
单例模式的实现方式:1.@classmethod def singleton(cls):
2.利用元类实现
1 # 单例模式: 2 # 实现方式一: 3 # class MySQL: 4 # __instance = None # __instance = obj1 5 # 6 # def __init__(self): 7 # self.host = '127.0.0.1' 8 # self.port = 3306 9 # 10 # @classmethod 11 # def singleton(cls): 12 # if not cls.__instance: 13 # obj = cls() 14 # cls.__instance = obj 15 # return cls.__instance 16 # 17 # def conn(self): 18 # pass 19 # 20 # def execute(self): 21 # pass 22 # 23 # # obj1 = MySQL() 24 # # obj2 = MySQL() 25 # # obj3 = MySQL() 26 # 27 # # print(obj1) 28 # # print(obj2) 29 # # print(obj3) 30 # # <__main__.MySQL object at 0x002CF6F0> 31 # # <__main__.MySQL object at 0x002CF6D0> 32 # # <__main__.MySQL object at 0x002CFF30> 33 # 34 # obj1 = MySQL.singleton() 35 # obj2 = MySQL.singleton() 36 # obj3 = MySQL.singleton() 37 # 38 # print(obj1) 39 # print(obj2) 40 # print(obj3) 41 # # <__main__.MySQL object at 0x01EAFF70> 42 # # <__main__.MySQL object at 0x01EAFF70> 43 # # <__main__.MySQL object at 0x01EAFF70> 44 45 # 实现方式二:元类的方式 46 47 class Mymeta(type): 48 def __init__(self,class_name,class_bases,class_dic): 49 if not class_name.istitle(): 50 raise TypeError('类名的首字母必须为大写') 51 52 if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): 53 raise TypeError('必须有注释,且注释不能为空') 54 super(Mymeta,self).__init__(class_name,class_bases,class_dic) 55 self.__instance = None 56 57 58 def __call__(self, *args, **kwargs): # obj = Chinese('egon',18) 59 if not self.__instance: 60 obj = object.__new__(self) 61 self.__init__(obj,*args,**kwargs) 62 self.__instance = obj 63 return self.__instance 64 65 class Mysql(object,metaclass=Mymeta): 66 '''1''' 67 def __init__(self): 68 self.host = '127.0.0.1' 69 self.port = 3306 70 71 def conn(self): 72 pass 73 74 def execute(self): 75 pass 76 77 obj1 = Mysql() 78 obj2 = Mysql() 79 obj3 = Mysql() 80 print(obj1) 81 print(obj2) 82 print(obj3) 83 # <__main__.Mysql object at 0x0034C090> 84 # <__main__.Mysql object at 0x0034C090> 85 # <__main__.Mysql object at 0x0034C090>