第五章-面向对象-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>

 

 
 
posted @ 2018-04-27 22:45  mumupa0824  阅读(182)  评论(0编辑  收藏  举报