Day 5-8 自定义元类控制类的实例化行为
__call__方法:
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 class Foo:
2
3 def __init__(self):
4 pass
5
6
7 def __call__(self, *args, **kwargs): # 在类中,使用__call__方法,表示实例化的对象可以被调用,也可以传参数进来.
8 print(args)
9 print(kwargs)
10
11
12
13
14 obj = Foo() #obj是由Foo类实例化得来的.那么Foo也是可以被调用的.那么Foo的类的内部也应该有一个__call__的方法.
那么Foo的类是元类type,那么type内部肯定也有一个__call__方法
15
16 #Foo是由元类实例化得来的,所以元类内部也有一个__call__方法,会在调用Foo的时候触发执行
17 #Foo(1,2,3)等价于 Foo__call__(Foo,1,2,3)
18 obj(1,2,3,x=99,y=100) # 传参到__call__方法中,相当于obj.__call__(obj, 1,2,3,x=99,y=100)
打印输出: (1, 2, 3) {'x': 99, 'y': 100}
自定义元类控制类的实例化行为:
1 class Mymeta(type): # 继承默认元类的一堆属性
2 def __init__(self,class_name, class_body, class_dic):
3 if not class_name.istitle():
4 raise TypeError("类名首字母必须大写!")
5
6 if "__doc__" not in class_dic or not class_dic["__doc__"].strip():
7 raise TypeError("必须有注释,且注释不能为空!")
8
9 super().__init__(class_name, class_body, class_dic)
10
11
12 def __call__(self, *args, **kwargs):#Chinese.__call__(Chinese,"jack",18)
13 # print("__call__ in Mymeta")
14 print(self) # Chinese
15 print(args) # "jack",18
16 print(kwargs) #{}
17 #实际上是在__call__做了3件事
18 #1.创建一个空对象
19 obj = object.__new__(self) # self =Chinese
20 #2.初始化对象
21 self.__init__(obj, *args, **kwargs)
22 #3.返回对象
23 return obj
24
25
26
27 class Chinese(object, metaclass=Mymeta):
28 """
29 休息休息
30 """
31 def __init__(self, name, age):
32 self.name = name
33 self.age = age
34
35 def tell(self):
36 print("name:%s,age:%s" % (self.name, self.age))
37
38
39
40
41 obj1 = Chinese("jack",18) # Chinese.__call__(Chinese,"jack",18) 相当于调用mymeta下的__call__方法.
单例模式:
1 # 单例模式
2
3
4 class MySql:
5 __instance =None
6 def __init__(self):
7 self.host = "127.0.0.1"
8 self.port = "3306"
9
10
11 @classmethod
12 def singeton(cls):
13 if not cls.__instance : # 检测如果__instance没有值.为None!如果一个对象中的元素是None,not 对象,则返回False
14 # print("s",cls.__instance)
15 obj =cls() # 就实例化一个对象
16 cls.__instance =obj # 把实例化对象的值赋给cls__instance
17 return cls.__instance
18
19 sql1 = MySql.singeton()
20 sql2 = MySql.singeton()
21 print(sql1 is sql2)
22 print(id(sql1))
23 print(id(sql2))
24 """
25 # 由于sql1和sql2都是由MySql实例化得来的,而且它们的参数都是一样的.这样实例化对象,太浪费内存空间了.
我们之前学过a = 1, b =a
26 其实a,b都指向了1的内存地址.那么我们在实例化相同参数的对象时,也可以使用这种方法.