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 # print(locals())
3
4 # g={
5 # 'x':1,
6 # 'y':2
7 # }
8 # l={}
9 # exec("""
10 # global x,m
11 # x=10
12 # m=100
13 #
14 # z=3
15 # """,g,l)
16 # # print(g)
17 # print(l)
18
19 # ----------------------------------------------------------
20 # 类也是对象,Foo=type()
21 # class Foo:
22 # pass
23 #
24 # obj=Foo()
25 # print(type)
26 # print(type(Foo))
27 # print(type(obj))
28
29 # class Bar:
30 # pass
31 # print(type(Bar))
32
33 # ----------------------------------------------------------
34 # 产生类得第一种方式: class
35 class Chinese: # 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
46 # print(Chinese)
47 obj=Chinese('alice',12)
48 print(obj,obj.name,obj.age)
49
50 # 产生类得第二种方式: type
51 # 定义类得三要素:类名,类的基类们,类得名称空间
52 class_name='Chinese'
53 class_bases=(object,)
54 class_body="""
55 country='China'
56
57 def __init__(self,name,age):
58 self.name=name
59 self.age=age
60
61 def talk(self):
62 print('%s is talking'%self.name)
63 """
64 class_dic={}
65 exec(class_body,globals(),class_dic)
66 # print(class_dic)
67
68 Chinese1=type(class_name,class_bases,class_dic) # 实例化了元类 得到了一个 元类得对象
69 # print(Chinese.__dict__)
70 # print(Chinese1)
71 obj1=Chinese1('alice',18)
72 print(obj1,obj1.name,obj1.age)
2.自定义元类控制类的行为
自定义元类 来控制 类的行为 控制类的创建行为
1 class Mymeta(type):
2 def __init__(self,class_name,class_bases,class_dic):
3 if not class_name.istitle():
4 raise TypeError('类名的首字母必须大写')
5 if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
6 raise TypeError('必须有注释,且注释不能为空!')
7 print(class_name)
8 print(class_bases)
9 print(class_dic)
10 super(Mymeta,self).__init__(class_name,class_bases,class_dic)
11
12
13 class Chinese(object,metaclass=Mymeta):
14 '''
15 中文人的类
16 '''
17 country='China'
18
19 def __init__(self,name,age):
20 self.name=name
21 self.age=age
22
23 def talk(self):
24 print('%s is talking'%self.name)
25
26 # Chinese=Mymeta(class_name,class_bases,class_dir)
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 # class Foo: #(元类 ype )
2 # def __call__(self, *args, **kwargs):
3 # print(self)
4 # print(args)
5 # print(kwargs)
6 # obj=Foo()
7 # obj(1,2,3,a=1,b=2,c=3) # 对象在调用时 会触发 __call__ #obj.__call__(obj,1,2,3,a=1,b=2,c=3)
8
9 # 得出结论是:元类内部也应该有一个 __call__方法 会在调用Foo时触发执行
10 # Foo(1,2,x=1) 触发 # Foo.__call__(Foo,1,2,x=1) 控制类的调用
11 # 所以:元类里有__call__() 控制类的实例化(产生对象)
12
13 # ----------------------------------------------------------
14 class Mymeta(type): #元类
15 def __init__(self,class_name,class_bases,class_dic): # 控制类的创建
16 if not class_name.istitle():
17 raise TypeError('类名的首字母必须大写')
18 if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
19 raise TypeError('必须有注释,且注释不能为空!')
20 # print(class_name)
21 # print(class_bases)
22 # print(class_dic)
23 super(Mymeta,self).__init__(class_name,class_bases,class_dic)
24
25 def __call__(self, *args, **kwargs): #obj=Chinese('alice',age=18) #控制类的实例化
26 # print(self) # <class '__main__.Chinese'>
27 # print(args) #('alice',)
28 # print(kwargs) #{'age': 18}
29 # 1.先造一个空对象
30 obj=object.__new__(self)
31 # 2.初始化obj
32 self.__init__(obj,*args,**kwargs)
33 # 3.返回obj
34 return obj
35
36
37 class Chinese(object,metaclass=Mymeta):
38 '''
39 中文人的类
40 '''
41 country='China'
42
43 def __init__(self,name,age):
44 self.name=name
45 self.age=age
46
47 def talk(self):
48 print('%s is talking'%self.name)
49
50 obj=Chinese('alice',age=18) # 触发Chinese.__call__(Chinese,'alice',18)
51 #生成对象步骤 --》 #1.先造空对象 2.初始化 3.返回值
52 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 # def __init__(self):
6 # self.host='127.0.0.1'
7 # self.port=3306
8 #
9 # @classmethod
10 # def singleton(cls):
11 # if not cls.__instance:
12 # obj=cls()
13 # cls.__instance=obj
14 # return cls.__instance
15 #
16 #
17 # def conn(self):
18 # pass
19 #
20 # def execute(self):
21 # pass
22 #
23 # # obj1=MySQL()
24 # # obj2=MySQL()
25 # #
26 # # print(obj1)
27 # # print(obj2)
28 #
29 # obj1=MySQL.singleton()
30 # obj2=MySQL.singleton()
31 #
32 # print(obj1.host)
33 # print(obj2)
34 # print(obj1 is obj2)
35
36 # --------------------------------------------------------
37 # 实现方式二:通过元类 实现了单例模式
38 class Mymeta(type):
39 def __init__(self,class_name,class_bases,class_dic): #控制类的创建
40 if not class_name.istitle():
41 raise TypeError('类名的首字母必须大写')
42 if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
43 raise TypeError('必须有注释,且注释不能为空!')
44 super(Mymeta,self).__init__(class_name,class_bases,class_dic)
45 self.__instance=None
46
47 def __call__(self, *args, **kwargs): #控制类的实例化
48 if not self.__instance:
49 obj=object.__new__(self)
50 self.__init__(obj)
51 self.__instance=obj
52 return self.__instance
53
54
55
56 class Mysql(object,metaclass=Mymeta):
57 '''
58 类的单例模式
59 '''
60 def __init__(self):
61 self.host='127.0.0.1'
62 self.port=3306
63
64 def conn(self):
65 pass
66
67 def execute(self):
68 pass
69
70 obj1=Mysql() # 在这个对象(Mysql)的类里面调用__call_()方法
71 obj2=Mysql()
72 obj3=Mysql()
73
74 print(obj1 is obj2 is obj3)